(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.echarts = {}));
})(this, function (exports) {
  'use strict';
  /*! *****************************************************************************
  Copyright (c) Microsoft Corporation. All rights reserved.
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
  this file except in compliance with the License. You may obtain a copy of the
  License at http://www.apache.org/licenses/LICENSE-2.0
    THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  MERCHANTABLITY OR NON-INFRINGEMENT.
    See the Apache Version 2.0 License for specific language governing permissions
  and limitations under the License.
  ***************************************************************************** */

  /* global Reflect, Promise */

  var extendStatics = function (d, b) {
    extendStatics = Object.setPrototypeOf || {
      __proto__: []
    } instanceof Array && function (d, b) {
      d.__proto__ = b;
    } || function (d, b) {
      for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    };

    return extendStatics(d, b);
  };

  function __extends(d, b) {
    extendStatics(d, b);

    function __() {
      this.constructor = d;
    }

    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  }

  function __spreadArrays() {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;

    for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j];

    return r;
  }

  var Browser = function () {
    function Browser() {
      this.firefox = false;
      this.ie = false;
      this.edge = false;
      this.weChat = false;
    }

    return Browser;
  }();

  var Env = function () {
    function Env() {
      this.browser = new Browser();
      this.node = false;
      this.wxa = false;
      this.worker = false;
      this.canvasSupported = false;
      this.svgSupported = false;
      this.touchEventsSupported = false;
      this.pointerEventsSupported = false;
      this.domSupported = false;
    }

    return Env;
  }();

  var env = new Env();

  if (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') {
    env.wxa = true;
    env.canvasSupported = true;
    env.touchEventsSupported = true;
  } else if (typeof document === 'undefined' && typeof self !== 'undefined') {
    env.worker = true;
    env.canvasSupported = true;
  } else if (typeof navigator === 'undefined') {
    env.node = true;
    env.canvasSupported = true;
    env.svgSupported = true;
  } else {
    detect(navigator.userAgent, env);
  }

  function detect(ua, env) {
    var browser = env.browser;
    var firefox = ua.match(/Firefox\/([\d.]+)/);
    var ie = ua.match(/MSIE\s([\d.]+)/) || ua.match(/Trident\/.+?rv:(([\d.]+))/);
    var edge = ua.match(/Edge\/([\d.]+)/);
    var weChat = /micromessenger/i.test(ua);

    if (firefox) {
      browser.firefox = true;
      browser.version = firefox[1];
    }

    if (ie) {
      browser.ie = true;
      browser.version = ie[1];
    }

    if (edge) {
      browser.edge = true;
      browser.version = edge[1];
    }

    if (weChat) {
      browser.weChat = true;
    }

    env.canvasSupported = !!document.createElement('canvas').getContext;
    env.svgSupported = typeof SVGRect !== 'undefined';
    env.touchEventsSupported = 'ontouchstart' in window && !browser.ie && !browser.edge;
    env.pointerEventsSupported = 'onpointerdown' in window && (browser.edge || browser.ie && +browser.version >= 11);
    env.domSupported = typeof document !== 'undefined';
  }

  var BUILTIN_OBJECT = {
    '[object Function]': true,
    '[object RegExp]': true,
    '[object Date]': true,
    '[object Error]': true,
    '[object CanvasGradient]': true,
    '[object CanvasPattern]': true,
    '[object Image]': true,
    '[object Canvas]': true
  };
  var TYPED_ARRAY = {
    '[object Int8Array]': true,
    '[object Uint8Array]': true,
    '[object Uint8ClampedArray]': true,
    '[object Int16Array]': true,
    '[object Uint16Array]': true,
    '[object Int32Array]': true,
    '[object Uint32Array]': true,
    '[object Float32Array]': true,
    '[object Float64Array]': true
  };
  var objToString = Object.prototype.toString;
  var arrayProto = Array.prototype;
  var nativeForEach = arrayProto.forEach;
  var nativeFilter = arrayProto.filter;
  var nativeSlice = arrayProto.slice;
  var nativeMap = arrayProto.map;

  var ctorFunction = function () {}.constructor;

  var protoFunction = ctorFunction ? ctorFunction.prototype : null;
  var methods = {};

  function $override(name, fn) {
    methods[name] = fn;
  }

  var idStart = 0x0907;

  function guid() {
    return idStart++;
  }

  function logError() {
    var args = [];

    for (var _i = 0; _i < arguments.length; _i++) {
      args[_i] = arguments[_i];
    }

    if (typeof console !== 'undefined') {
      console.error.apply(args);
    }
  }

  function clone(source) {
    if (source == null || typeof source !== 'object') {
      return source;
    }

    var result = source;
    var typeStr = objToString.call(source);

    if (typeStr === '[object Array]') {
      if (!isPrimitive(source)) {
        result = [];

        for (var i = 0, len = source.length; i < len; i++) {
          result[i] = clone(source[i]);
        }
      }
    } else if (TYPED_ARRAY[typeStr]) {
      if (!isPrimitive(source)) {
        var Ctor = source.constructor;

        if (Ctor.from) {
          result = Ctor.from(source);
        } else {
          result = new Ctor(source.length);

          for (var i = 0, len = source.length; i < len; i++) {
            result[i] = clone(source[i]);
          }
        }
      }
    } else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {
      result = {};

      for (var key in source) {
        if (source.hasOwnProperty(key)) {
          result[key] = clone(source[key]);
        }
      }
    }

    return result;
  }

  function merge(target, source, overwrite) {
    if (!isObject(source) || !isObject(target)) {
      return overwrite ? clone(source) : target;
    }

    for (var key in source) {
      if (source.hasOwnProperty(key)) {
        var targetProp = target[key];
        var sourceProp = source[key];

        if (isObject(sourceProp) && isObject(targetProp) && !isArray(sourceProp) && !isArray(targetProp) && !isDom(sourceProp) && !isDom(targetProp) && !isBuiltInObject(sourceProp) && !isBuiltInObject(targetProp) && !isPrimitive(sourceProp) && !isPrimitive(targetProp)) {
          merge(targetProp, sourceProp, overwrite);
        } else if (overwrite || !(key in target)) {
          target[key] = clone(source[key]);
        }
      }
    }

    return target;
  }

  function extend(target, source) {
    if (Object.assign) {
      Object.assign(target, source);
    } else {
      for (var key in source) {
        if (source.hasOwnProperty(key)) {
          target[key] = source[key];
        }
      }
    }

    return target;
  }

  function defaults(target, source, overlay) {
    var keysArr = keys(source);

    for (var i = 0; i < keysArr.length; i++) {
      var key = keysArr[i];

      if (overlay ? source[key] != null : target[key] == null) {
        target[key] = source[key];
      }
    }

    return target;
  }

  var createCanvas = function () {
    return methods.createCanvas();
  };

  methods.createCanvas = function () {
    return document.createElement('canvas');
  };

  function indexOf(array, value) {
    if (array) {
      if (array.indexOf) {
        return array.indexOf(value);
      }

      for (var i = 0, len = array.length; i < len; i++) {
        if (array[i] === value) {
          return i;
        }
      }
    }

    return -1;
  }

  function inherits(clazz, baseClazz) {
    var clazzPrototype = clazz.prototype;

    function F() {}

    F.prototype = baseClazz.prototype;
    clazz.prototype = new F();

    for (var prop in clazzPrototype) {
      if (clazzPrototype.hasOwnProperty(prop)) {
        clazz.prototype[prop] = clazzPrototype[prop];
      }
    }

    clazz.prototype.constructor = clazz;
    clazz.superClass = baseClazz;
  }

  function mixin(target, source, override) {
    target = 'prototype' in target ? target.prototype : target;
    source = 'prototype' in source ? source.prototype : source;

    if (Object.getOwnPropertyNames) {
      var keyList = Object.getOwnPropertyNames(source);

      for (var i = 0; i < keyList.length; i++) {
        var key = keyList[i];

        if (key !== 'constructor') {
          if (override ? source[key] != null : target[key] == null) {
            target[key] = source[key];
          }
        }
      }
    } else {
      defaults(target, source, override);
    }
  }

  function isArrayLike(data) {
    if (!data) {
      return false;
    }

    if (typeof data === 'string') {
      return false;
    }

    return typeof data.length === 'number';
  }

  function each(arr, cb, context) {
    if (!(arr && cb)) {
      return;
    }

    if (arr.forEach && arr.forEach === nativeForEach) {
      arr.forEach(cb, context);
    } else if (arr.length === +arr.length) {
      for (var i = 0, len = arr.length; i < len; i++) {
        cb.call(context, arr[i], i, arr);
      }
    } else {
      for (var key in arr) {
        if (arr.hasOwnProperty(key)) {
          cb.call(context, arr[key], key, arr);
        }
      }
    }
  }

  function map(arr, cb, context) {
    if (!arr) {
      return [];
    }

    if (!cb) {
      return slice(arr);
    }

    if (arr.map && arr.map === nativeMap) {
      return arr.map(cb, context);
    } else {
      var result = [];

      for (var i = 0, len = arr.length; i < len; i++) {
        result.push(cb.call(context, arr[i], i, arr));
      }

      return result;
    }
  }

  function reduce(arr, cb, memo, context) {
    if (!(arr && cb)) {
      return;
    }

    for (var i = 0, len = arr.length; i < len; i++) {
      memo = cb.call(context, memo, arr[i], i, arr);
    }

    return memo;
  }

  function filter(arr, cb, context) {
    if (!arr) {
      return [];
    }

    if (!cb) {
      return slice(arr);
    }

    if (arr.filter && arr.filter === nativeFilter) {
      return arr.filter(cb, context);
    } else {
      var result = [];

      for (var i = 0, len = arr.length; i < len; i++) {
        if (cb.call(context, arr[i], i, arr)) {
          result.push(arr[i]);
        }
      }

      return result;
    }
  }

  function keys(obj) {
    if (!obj) {
      return [];
    }

    if (Object.keys) {
      return Object.keys(obj);
    }

    var keyList = [];

    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        keyList.push(key);
      }
    }

    return keyList;
  }

  function bindPolyfill(func, context) {
    var args = [];

    for (var _i = 2; _i < arguments.length; _i++) {
      args[_i - 2] = arguments[_i];
    }

    return function () {
      return func.apply(context, args.concat(nativeSlice.call(arguments)));
    };
  }

  var bind = protoFunction && isFunction(protoFunction.bind) ? protoFunction.call.bind(protoFunction.bind) : bindPolyfill;

  function curry(func) {
    var args = [];

    for (var _i = 1; _i < arguments.length; _i++) {
      args[_i - 1] = arguments[_i];
    }

    return function () {
      return func.apply(this, args.concat(nativeSlice.call(arguments)));
    };
  }

  function isArray(value) {
    if (Array.isArray) {
      return Array.isArray(value);
    }

    return objToString.call(value) === '[object Array]';
  }

  function isFunction(value) {
    return typeof value === 'function';
  }

  function isString(value) {
    return typeof value === 'string';
  }

  function isStringSafe(value) {
    return objToString.call(value) === '[object String]';
  }

  function isNumber(value) {
    return typeof value === 'number';
  }

  function isObject(value) {
    var type = typeof value;
    return type === 'function' || !!value && type === 'object';
  }

  function isBuiltInObject(value) {
    return !!BUILTIN_OBJECT[objToString.call(value)];
  }

  function isTypedArray(value) {
    return !!TYPED_ARRAY[objToString.call(value)];
  }

  function isDom(value) {
    return typeof value === 'object' && typeof value.nodeType === 'number' && typeof value.ownerDocument === 'object';
  }

  function isGradientObject(value) {
    return value.colorStops != null;
  }

  function isPatternObject(value) {
    return value.image != null;
  }

  function isRegExp(value) {
    return objToString.call(value) === '[object RegExp]';
  }

  function eqNaN(value) {
    return value !== value;
  }

  function retrieve() {
    var args = [];

    for (var _i = 0; _i < arguments.length; _i++) {
      args[_i] = arguments[_i];
    }

    for (var i = 0, len = args.length; i < len; i++) {
      if (args[i] != null) {
        return args[i];
      }
    }
  }

  function retrieve2(value0, value1) {
    return value0 != null ? value0 : value1;
  }

  function retrieve3(value0, value1, value2) {
    return value0 != null ? value0 : value1 != null ? value1 : value2;
  }

  function slice(arr) {
    var args = [];

    for (var _i = 1; _i < arguments.length; _i++) {
      args[_i - 1] = arguments[_i];
    }

    return nativeSlice.apply(arr, args);
  }

  function normalizeCssArray(val) {
    if (typeof val === 'number') {
      return [val, val, val, val];
    }

    var len = val.length;

    if (len === 2) {
      return [val[0], val[1], val[0], val[1]];
    } else if (len === 3) {
      return [val[0], val[1], val[2], val[1]];
    }

    return val;
  }

  function assert(condition, message) {
    if (!condition) {
      throw new Error(message);
    }
  }

  function trim(str) {
    if (str == null) {
      return null;
    } else if (typeof str.trim === 'function') {
      return str.trim();
    } else {
      return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
    }
  }

  var primitiveKey = '__ec_primitive__';

  function setAsPrimitive(obj) {
    obj[primitiveKey] = true;
  }

  function isPrimitive(obj) {
    return obj[primitiveKey];
  }

  var HashMap = function () {
    function HashMap(obj) {
      this.data = {};
      var isArr = isArray(obj);
      this.data = {};
      var thisMap = this;
      obj instanceof HashMap ? obj.each(visit) : obj && each(obj, visit);

      function visit(value, key) {
        isArr ? thisMap.set(value, key) : thisMap.set(key, value);
      }
    }

    HashMap.prototype.get = function (key) {
      return this.data.hasOwnProperty(key) ? this.data[key] : null;
    };

    HashMap.prototype.set = function (key, value) {
      return this.data[key] = value;
    };

    HashMap.prototype.each = function (cb, context) {
      for (var key in this.data) {
        if (this.data.hasOwnProperty(key)) {
          cb.call(context, this.data[key], key);
        }
      }
    };

    HashMap.prototype.keys = function () {
      return keys(this.data);
    };

    HashMap.prototype.removeKey = function (key) {
      delete this.data[key];
    };

    return HashMap;
  }();

  function createHashMap(obj) {
    return new HashMap(obj);
  }

  function createObject(proto, properties) {
    var obj;

    if (Object.create) {
      obj = Object.create(proto);
    } else {
      var StyleCtor = function () {};

      StyleCtor.prototype = proto;
      obj = new StyleCtor();
    }

    if (properties) {
      extend(obj, properties);
    }

    return obj;
  }

  function hasOwn(own, prop) {
    return own.hasOwnProperty(prop);
  }

  function noop() {}

  function create(x, y) {
    if (x == null) {
      x = 0;
    }

    if (y == null) {
      y = 0;
    }

    return [x, y];
  }

  function copy(out, v) {
    out[0] = v[0];
    out[1] = v[1];
    return out;
  }

  function clone$1(v) {
    return [v[0], v[1]];
  }

  function add(out, v1, v2) {
    out[0] = v1[0] + v2[0];
    out[1] = v1[1] + v2[1];
    return out;
  }

  function scaleAndAdd(out, v1, v2, a) {
    out[0] = v1[0] + v2[0] * a;
    out[1] = v1[1] + v2[1] * a;
    return out;
  }

  function sub(out, v1, v2) {
    out[0] = v1[0] - v2[0];
    out[1] = v1[1] - v2[1];
    return out;
  }

  function len(v) {
    return Math.sqrt(lenSquare(v));
  }

  function lenSquare(v) {
    return v[0] * v[0] + v[1] * v[1];
  }

  function scale(out, v, s) {
    out[0] = v[0] * s;
    out[1] = v[1] * s;
    return out;
  }

  function normalize(out, v) {
    var d = len(v);

    if (d === 0) {
      out[0] = 0;
      out[1] = 0;
    } else {
      out[0] = v[0] / d;
      out[1] = v[1] / d;
    }

    return out;
  }

  function distance(v1, v2) {
    return Math.sqrt((v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]));
  }

  var dist = distance;

  function distanceSquare(v1, v2) {
    return (v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]);
  }

  var distSquare = distanceSquare;

  function lerp(out, v1, v2, t) {
    out[0] = v1[0] + t * (v2[0] - v1[0]);
    out[1] = v1[1] + t * (v2[1] - v1[1]);
    return out;
  }

  function applyTransform(out, v, m) {
    var x = v[0];
    var y = v[1];
    out[0] = m[0] * x + m[2] * y + m[4];
    out[1] = m[1] * x + m[3] * y + m[5];
    return out;
  }

  function min(out, v1, v2) {
    out[0] = Math.min(v1[0], v2[0]);
    out[1] = Math.min(v1[1], v2[1]);
    return out;
  }

  function max(out, v1, v2) {
    out[0] = Math.max(v1[0], v2[0]);
    out[1] = Math.max(v1[1], v2[1]);
    return out;
  }

  var Param = function () {
    function Param(target, e) {
      this.target = target;
      this.topTarget = e && e.topTarget;
    }

    return Param;
  }();

  var Draggable = function () {
    function Draggable(handler) {
      this.handler = handler;
      handler.on('mousedown', this._dragStart, this);
      handler.on('mousemove', this._drag, this);
      handler.on('mouseup', this._dragEnd, this);
    }

    Draggable.prototype._dragStart = function (e) {
      var draggingTarget = e.target;

      while (draggingTarget && !draggingTarget.draggable) {
        draggingTarget = draggingTarget.parent;
      }

      if (draggingTarget) {
        this._draggingTarget = draggingTarget;
        draggingTarget.dragging = true;
        this._x = e.offsetX;
        this._y = e.offsetY;
        this.handler.dispatchToElement(new Param(draggingTarget, e), 'dragstart', e.event);
      }
    };

    Draggable.prototype._drag = function (e) {
      var draggingTarget = this._draggingTarget;

      if (draggingTarget) {
        var x = e.offsetX;
        var y = e.offsetY;
        var dx = x - this._x;
        var dy = y - this._y;
        this._x = x;
        this._y = y;
        draggingTarget.drift(dx, dy, e);
        this.handler.dispatchToElement(new Param(draggingTarget, e), 'drag', e.event);
        var dropTarget = this.handler.findHover(x, y, draggingTarget).target;
        var lastDropTarget = this._dropTarget;
        this._dropTarget = dropTarget;

        if (draggingTarget !== dropTarget) {
          if (lastDropTarget && dropTarget !== lastDropTarget) {
            this.handler.dispatchToElement(new Param(lastDropTarget, e), 'dragleave', e.event);
          }

          if (dropTarget && dropTarget !== lastDropTarget) {
            this.handler.dispatchToElement(new Param(dropTarget, e), 'dragenter', e.event);
          }
        }
      }
    };

    Draggable.prototype._dragEnd = function (e) {
      var draggingTarget = this._draggingTarget;

      if (draggingTarget) {
        draggingTarget.dragging = false;
      }

      this.handler.dispatchToElement(new Param(draggingTarget, e), 'dragend', e.event);

      if (this._dropTarget) {
        this.handler.dispatchToElement(new Param(this._dropTarget, e), 'drop', e.event);
      }

      this._draggingTarget = null;
      this._dropTarget = null;
    };

    return Draggable;
  }();

  var Eventful = function () {
    function Eventful(eventProcessors) {
      if (eventProcessors) {
        this._$eventProcessor = eventProcessors;
      }
    }

    Eventful.prototype.on = function (event, query, handler, context) {
      if (!this._$handlers) {
        this._$handlers = {};
      }

      var _h = this._$handlers;

      if (typeof query === 'function') {
        context = handler;
        handler = query;
        query = null;
      }

      if (!handler || !event) {
        return this;
      }

      var eventProcessor = this._$eventProcessor;

      if (query != null && eventProcessor && eventProcessor.normalizeQuery) {
        query = eventProcessor.normalizeQuery(query);
      }

      if (!_h[event]) {
        _h[event] = [];
      }

      for (var i = 0; i < _h[event].length; i++) {
        if (_h[event][i].h === handler) {
          return this;
        }
      }

      var wrap = {
        h: handler,
        query: query,
        ctx: context || this,
        callAtLast: handler.zrEventfulCallAtLast
      };
      var lastIndex = _h[event].length - 1;
      var lastWrap = _h[event][lastIndex];
      lastWrap && lastWrap.callAtLast ? _h[event].splice(lastIndex, 0, wrap) : _h[event].push(wrap);
      return this;
    };

    Eventful.prototype.isSilent = function (eventName) {
      var _h = this._$handlers;
      return !_h || !_h[eventName] || !_h[eventName].length;
    };

    Eventful.prototype.off = function (eventType, handler) {
      var _h = this._$handlers;

      if (!_h) {
        return this;
      }

      if (!eventType) {
        this._$handlers = {};
        return this;
      }

      if (handler) {
        if (_h[eventType]) {
          var newList = [];

          for (var i = 0, l = _h[eventType].length; i < l; i++) {
            if (_h[eventType][i].h !== handler) {
              newList.push(_h[eventType][i]);
            }
          }

          _h[eventType] = newList;
        }

        if (_h[eventType] && _h[eventType].length === 0) {
          delete _h[eventType];
        }
      } else {
        delete _h[eventType];
      }

      return this;
    };

    Eventful.prototype.trigger = function (eventType) {
      var args = [];

      for (var _i = 1; _i < arguments.length; _i++) {
        args[_i - 1] = arguments[_i];
      }

      if (!this._$handlers) {
        return this;
      }

      var _h = this._$handlers[eventType];
      var eventProcessor = this._$eventProcessor;

      if (_h) {
        var argLen = args.length;
        var len = _h.length;

        for (var i = 0; i < len; i++) {
          var hItem = _h[i];

          if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(eventType, hItem.query)) {
            i++;
            continue;
          }

          switch (argLen) {
            case 0:
              hItem.h.call(hItem.ctx);
              break;

            case 1:
              hItem.h.call(hItem.ctx, args[0]);
              break;

            case 2:
              hItem.h.call(hItem.ctx, args[0], args[1]);
              break;

            default:
              hItem.h.apply(hItem.ctx, args);
              break;
          }
        }
      }

      eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(eventType);
      return this;
    };

    Eventful.prototype.triggerWithContext = function (type) {
      if (!this._$handlers) {
        return this;
      }

      var _h = this._$handlers[type];
      var eventProcessor = this._$eventProcessor;

      if (_h) {
        var args = arguments;
        var argLen = args.length;
        var ctx = args[argLen - 1];
        var len = _h.length;

        for (var i = 0; i < len;) {
          var hItem = _h[i];

          if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(type, hItem.query)) {
            i++;
            continue;
          }

          switch (argLen) {
            case 0:
              hItem.h.call(ctx);
              break;

            case 1:
              hItem.h.call(ctx, args[0]);
              break;

            case 2:
              hItem.h.call(ctx, args[0], args[1]);
              break;

            default:
              hItem.h.apply(ctx, args.slice(1, argLen - 1));
              break;
          }
        }
      }

      eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(type);
      return this;
    };

    return Eventful;
  }();

  var LN2 = Math.log(2);

  function determinant(rows, rank, rowStart, rowMask, colMask, detCache) {
    var cacheKey = rowMask + '-' + colMask;
    var fullRank = rows.length;

    if (detCache.hasOwnProperty(cacheKey)) {
      return detCache[cacheKey];
    }

    if (rank === 1) {
      var colStart = Math.round(Math.log((1 << fullRank) - 1 & ~colMask) / LN2);
      return rows[rowStart][colStart];
    }

    var subRowMask = rowMask | 1 << rowStart;
    var subRowStart = rowStart + 1;

    while (rowMask & 1 << subRowStart) {
      subRowStart++;
    }

    var sum = 0;

    for (var j = 0, colLocalIdx = 0; j < fullRank; j++) {
      var colTag = 1 << j;

      if (!(colTag & colMask)) {
        sum += (colLocalIdx % 2 ? -1 : 1) * rows[rowStart][j] * determinant(rows, rank - 1, subRowStart, subRowMask, colMask | colTag, detCache);
        colLocalIdx++;
      }
    }

    detCache[cacheKey] = sum;
    return sum;
  }

  function buildTransformer(src, dest) {
    var mA = [[src[0], src[1], 1, 0, 0, 0, -dest[0] * src[0], -dest[0] * src[1]], [0, 0, 0, src[0], src[1], 1, -dest[1] * src[0], -dest[1] * src[1]], [src[2], src[3], 1, 0, 0, 0, -dest[2] * src[2], -dest[2] * src[3]], [0, 0, 0, src[2], src[3], 1, -dest[3] * src[2], -dest[3] * src[3]], [src[4], src[5], 1, 0, 0, 0, -dest[4] * src[4], -dest[4] * src[5]], [0, 0, 0, src[4], src[5], 1, -dest[5] * src[4], -dest[5] * src[5]], [src[6], src[7], 1, 0, 0, 0, -dest[6] * src[6], -dest[6] * src[7]], [0, 0, 0, src[6], src[7], 1, -dest[7] * src[6], -dest[7] * src[7]]];
    var detCache = {};
    var det = determinant(mA, 8, 0, 0, 0, detCache);

    if (det === 0) {
      return;
    }

    var vh = [];

    for (var i = 0; i < 8; i++) {
      for (var j = 0; j < 8; j++) {
        vh[j] == null && (vh[j] = 0);
        vh[j] += ((i + j) % 2 ? -1 : 1) * determinant(mA, 7, i === 0 ? 1 : 0, 1 << i, 1 << j, detCache) / det * dest[i];
      }
    }

    return function (out, srcPointX, srcPointY) {
      var pk = srcPointX * vh[6] + srcPointY * vh[7] + 1;
      out[0] = (srcPointX * vh[0] + srcPointY * vh[1] + vh[2]) / pk;
      out[1] = (srcPointX * vh[3] + srcPointY * vh[4] + vh[5]) / pk;
    };
  }

  var EVENT_SAVED_PROP = '___zrEVENTSAVED';

  function transformCoordWithViewport(out, el, inX, inY, inverse) {
    if (el.getBoundingClientRect && env.domSupported && !isCanvasEl(el)) {
      var saved = el[EVENT_SAVED_PROP] || (el[EVENT_SAVED_PROP] = {});
      var markers = prepareCoordMarkers(el, saved);
      var transformer = preparePointerTransformer(markers, saved, inverse);

      if (transformer) {
        transformer(out, inX, inY);
        return true;
      }
    }

    return false;
  }

  function prepareCoordMarkers(el, saved) {
    var markers = saved.markers;

    if (markers) {
      return markers;
    }

    markers = saved.markers = [];
    var propLR = ['left', 'right'];
    var propTB = ['top', 'bottom'];

    for (var i = 0; i < 4; i++) {
      var marker = document.createElement('div');
      var stl = marker.style;
      var idxLR = i % 2;
      var idxTB = (i >> 1) % 2;
      stl.cssText = ['position: absolute', 'visibility: hidden', 'padding: 0', 'margin: 0', 'border-width: 0', 'user-select: none', 'width:0', 'height:0', propLR[idxLR] + ':0', propTB[idxTB] + ':0', propLR[1 - idxLR] + ':auto', propTB[1 - idxTB] + ':auto', ''].join('!important;');
      el.appendChild(marker);
      markers.push(marker);
    }

    return markers;
  }

  function preparePointerTransformer(markers, saved, inverse) {
    var transformerName = inverse ? 'invTrans' : 'trans';
    var transformer = saved[transformerName];
    var oldSrcCoords = saved.srcCoords;
    var srcCoords = [];
    var destCoords = [];
    var oldCoordTheSame = true;

    for (var i = 0; i < 4; i++) {
      var rect = markers[i].getBoundingClientRect();
      var ii = 2 * i;
      var x = rect.left;
      var y = rect.top;
      srcCoords.push(x, y);
      oldCoordTheSame = oldCoordTheSame && oldSrcCoords && x === oldSrcCoords[ii] && y === oldSrcCoords[ii + 1];
      destCoords.push(markers[i].offsetLeft, markers[i].offsetTop);
    }

    return oldCoordTheSame && transformer ? transformer : (saved.srcCoords = srcCoords, saved[transformerName] = inverse ? buildTransformer(destCoords, srcCoords) : buildTransformer(srcCoords, destCoords));
  }

  function isCanvasEl(el) {
    return el.nodeName.toUpperCase() === 'CANVAS';
  }

  var isDomLevel2 = typeof window !== 'undefined' && !!window.addEventListener;
  var MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;
  var _calcOut = [];

  function clientToLocal(el, e, out, calculate) {
    out = out || {};

    if (calculate || !env.canvasSupported) {
      calculateZrXY(el, e, out);
    } else if (env.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {
      out.zrX = e.layerX;
      out.zrY = e.layerY;
    } else if (e.offsetX != null) {
      out.zrX = e.offsetX;
      out.zrY = e.offsetY;
    } else {
      calculateZrXY(el, e, out);
    }

    return out;
  }

  function calculateZrXY(el, e, out) {
    if (env.domSupported && el.getBoundingClientRect) {
      var ex = e.clientX;
      var ey = e.clientY;

      if (isCanvasEl(el)) {
        var box = el.getBoundingClientRect();
        out.zrX = ex - box.left;
        out.zrY = ey - box.top;
        return;
      } else {
        if (transformCoordWithViewport(_calcOut, el, ex, ey)) {
          out.zrX = _calcOut[0];
          out.zrY = _calcOut[1];
          return;
        }
      }
    }

    out.zrX = out.zrY = 0;
  }

  function getNativeEvent(e) {
    return e || window.event;
  }

  function normalizeEvent(el, e, calculate) {
    e = getNativeEvent(e);

    if (e.zrX != null) {
      return e;
    }

    var eventType = e.type;
    var isTouch = eventType && eventType.indexOf('touch') >= 0;

    if (!isTouch) {
      clientToLocal(el, e, e, calculate);
      var wheelDelta = getWheelDeltaMayPolyfill(e);
      e.zrDelta = wheelDelta ? wheelDelta / 120 : -(e.detail || 0) / 3;
    } else {
      var touch = eventType !== 'touchend' ? e.targetTouches[0] : e.changedTouches[0];
      touch && clientToLocal(el, touch, e, calculate);
    }

    var button = e.button;

    if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {
      e.which = button & 1 ? 1 : button & 2 ? 3 : button & 4 ? 2 : 0;
    }

    return e;
  }

  function getWheelDeltaMayPolyfill(e) {
    var rawWheelDelta = e.wheelDelta;

    if (rawWheelDelta) {
      return rawWheelDelta;
    }

    var deltaX = e.deltaX;
    var deltaY = e.deltaY;

    if (deltaX == null || deltaY == null) {
      return rawWheelDelta;
    }

    var delta = deltaY !== 0 ? Math.abs(deltaY) : Math.abs(deltaX);
    var sign = deltaY > 0 ? -1 : deltaY < 0 ? 1 : deltaX > 0 ? -1 : 1;
    return 3 * delta * sign;
  }

  function addEventListener(el, name, handler, opt) {
    if (isDomLevel2) {
      el.addEventListener(name, handler, opt);
    } else {
      el.attachEvent('on' + name, handler);
    }
  }

  function removeEventListener(el, name, handler, opt) {
    if (isDomLevel2) {
      el.removeEventListener(name, handler, opt);
    } else {
      el.detachEvent('on' + name, handler);
    }
  }

  var stop = isDomLevel2 ? function (e) {
    e.preventDefault();
    e.stopPropagation();
    e.cancelBubble = true;
  } : function (e) {
    e.returnValue = false;
    e.cancelBubble = true;
  };

  var GestureMgr = function () {
    function GestureMgr() {
      this._track = [];
    }

    GestureMgr.prototype.recognize = function (event, target, root) {
      this._doTrack(event, target, root);

      return this._recognize(event);
    };

    GestureMgr.prototype.clear = function () {
      this._track.length = 0;
      return this;
    };

    GestureMgr.prototype._doTrack = function (event, target, root) {
      var touches = event.touches;

      if (!touches) {
        return;
      }

      var trackItem = {
        points: [],
        touches: [],
        target: target,
        event: event
      };

      for (var i = 0, len = touches.length; i < len; i++) {
        var touch = touches[i];
        var pos = clientToLocal(root, touch, {});
        trackItem.points.push([pos.zrX, pos.zrY]);
        trackItem.touches.push(touch);
      }

      this._track.push(trackItem);
    };

    GestureMgr.prototype._recognize = function (event) {
      for (var eventName in recognizers) {
        if (recognizers.hasOwnProperty(eventName)) {
          var gestureInfo = recognizers[eventName](this._track, event);

          if (gestureInfo) {
            return gestureInfo;
          }
        }
      }
    };

    return GestureMgr;
  }();

  function dist$1(pointPair) {
    var dx = pointPair[1][0] - pointPair[0][0];
    var dy = pointPair[1][1] - pointPair[0][1];
    return Math.sqrt(dx * dx + dy * dy);
  }

  function center(pointPair) {
    return [(pointPair[0][0] + pointPair[1][0]) / 2, (pointPair[0][1] + pointPair[1][1]) / 2];
  }

  var recognizers = {
    pinch: function (tracks, event) {
      var trackLen = tracks.length;

      if (!trackLen) {
        return;
      }

      var pinchEnd = (tracks[trackLen - 1] || {}).points;
      var pinchPre = (tracks[trackLen - 2] || {}).points || pinchEnd;

      if (pinchPre && pinchPre.length > 1 && pinchEnd && pinchEnd.length > 1) {
        var pinchScale = dist$1(pinchEnd) / dist$1(pinchPre);
        !isFinite(pinchScale) && (pinchScale = 1);
        event.pinchScale = pinchScale;
        var pinchCenter = center(pinchEnd);
        event.pinchX = pinchCenter[0];
        event.pinchY = pinchCenter[1];
        return {
          type: 'pinch',
          target: tracks[0].target,
          event: event
        };
      }
    }
  };
  var SILENT = 'silent';

  function makeEventPacket(eveType, targetInfo, event) {
    return {
      type: eveType,
      event: event,
      target: targetInfo.target,
      topTarget: targetInfo.topTarget,
      cancelBubble: false,
      offsetX: event.zrX,
      offsetY: event.zrY,
      gestureEvent: event.gestureEvent,
      pinchX: event.pinchX,
      pinchY: event.pinchY,
      pinchScale: event.pinchScale,
      wheelDelta: event.zrDelta,
      zrByTouch: event.zrByTouch,
      which: event.which,
      stop: stopEvent
    };
  }

  function stopEvent() {
    stop(this.event);
  }

  var EmptyProxy = function (_super) {
    __extends(EmptyProxy, _super);

    function EmptyProxy() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.handler = null;
      return _this;
    }

    EmptyProxy.prototype.dispose = function () {};

    EmptyProxy.prototype.setCursor = function () {};

    return EmptyProxy;
  }(Eventful);

  var HoveredResult = function () {
    function HoveredResult(x, y) {
      this.x = x;
      this.y = y;
    }

    return HoveredResult;
  }();

  var handlerNames = ['click', 'dblclick', 'mousewheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu'];

  var Handler = function (_super) {
    __extends(Handler, _super);

    function Handler(storage, painter, proxy, painterRoot) {
      var _this = _super.call(this) || this;

      _this._hovered = new HoveredResult(0, 0);
      _this.storage = storage;
      _this.painter = painter;
      _this.painterRoot = painterRoot;
      proxy = proxy || new EmptyProxy();
      _this.proxy = null;

      _this.setHandlerProxy(proxy);

      _this._draggingMgr = new Draggable(_this);
      return _this;
    }

    Handler.prototype.setHandlerProxy = function (proxy) {
      if (this.proxy) {
        this.proxy.dispose();
      }

      if (proxy) {
        each(handlerNames, function (name) {
          proxy.on && proxy.on(name, this[name], this);
        }, this);
        proxy.handler = this;
      }

      this.proxy = proxy;
    };

    Handler.prototype.mousemove = function (event) {
      var x = event.zrX;
      var y = event.zrY;
      var isOutside = isOutsideBoundary(this, x, y);
      var lastHovered = this._hovered;
      var lastHoveredTarget = lastHovered.target;

      if (lastHoveredTarget && !lastHoveredTarget.__zr) {
        lastHovered = this.findHover(lastHovered.x, lastHovered.y);
        lastHoveredTarget = lastHovered.target;
      }

      var hovered = this._hovered = isOutside ? new HoveredResult(x, y) : this.findHover(x, y);
      var hoveredTarget = hovered.target;
      var proxy = this.proxy;
      proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default');

      if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) {
        this.dispatchToElement(lastHovered, 'mouseout', event);
      }

      this.dispatchToElement(hovered, 'mousemove', event);

      if (hoveredTarget && hoveredTarget !== lastHoveredTarget) {
        this.dispatchToElement(hovered, 'mouseover', event);
      }
    };

    Handler.prototype.mouseout = function (event) {
      var eventControl = event.zrEventControl;
      var zrIsToLocalDOM = event.zrIsToLocalDOM;

      if (eventControl !== 'only_globalout') {
        this.dispatchToElement(this._hovered, 'mouseout', event);
      }

      if (eventControl !== 'no_globalout') {
        !zrIsToLocalDOM && this.trigger('globalout', {
          type: 'globalout',
          event: event
        });
      }
    };

    Handler.prototype.resize = function () {
      this._hovered = new HoveredResult(0, 0);
    };

    Handler.prototype.dispatch = function (eventName, eventArgs) {
      var handler = this[eventName];
      handler && handler.call(this, eventArgs);
    };

    Handler.prototype.dispose = function () {
      this.proxy.dispose();
      this.storage = null;
      this.proxy = null;
      this.painter = null;
    };

    Handler.prototype.setCursorStyle = function (cursorStyle) {
      var proxy = this.proxy;
      proxy.setCursor && proxy.setCursor(cursorStyle);
    };

    Handler.prototype.dispatchToElement = function (targetInfo, eventName, event) {
      targetInfo = targetInfo || {};
      var el = targetInfo.target;

      if (el && el.silent) {
        return;
      }

      var eventKey = 'on' + eventName;
      var eventPacket = makeEventPacket(eventName, targetInfo, event);

      while (el) {
        el[eventKey] && (eventPacket.cancelBubble = !!el[eventKey].call(el, eventPacket));
        el.trigger(eventName, eventPacket);
        el = el.__hostTarget ? el.__hostTarget : el.parent;

        if (eventPacket.cancelBubble) {
          break;
        }
      }

      if (!eventPacket.cancelBubble) {
        this.trigger(eventName, eventPacket);

        if (this.painter && this.painter.eachOtherLayer) {
          this.painter.eachOtherLayer(function (layer) {
            if (typeof layer[eventKey] === 'function') {
              layer[eventKey].call(layer, eventPacket);
            }

            if (layer.trigger) {
              layer.trigger(eventName, eventPacket);
            }
          });
        }
      }
    };

    Handler.prototype.findHover = function (x, y, exclude) {
      var list = this.storage.getDisplayList();
      var out = new HoveredResult(x, y);

      for (var i = list.length - 1; i >= 0; i--) {
        var hoverCheckResult = void 0;

        if (list[i] !== exclude && !list[i].ignore && (hoverCheckResult = isHover(list[i], x, y))) {
          !out.topTarget && (out.topTarget = list[i]);

          if (hoverCheckResult !== SILENT) {
            out.target = list[i];
            break;
          }
        }
      }

      return out;
    };

    Handler.prototype.processGesture = function (event, stage) {
      if (!this._gestureMgr) {
        this._gestureMgr = new GestureMgr();
      }

      var gestureMgr = this._gestureMgr;
      stage === 'start' && gestureMgr.clear();
      var gestureInfo = gestureMgr.recognize(event, this.findHover(event.zrX, event.zrY, null).target, this.proxy.dom);
      stage === 'end' && gestureMgr.clear();

      if (gestureInfo) {
        var type = gestureInfo.type;
        event.gestureEvent = type;
        var res = new HoveredResult();
        res.target = gestureInfo.target;
        this.dispatchToElement(res, type, gestureInfo.event);
      }
    };

    return Handler;
  }(Eventful);

  each(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
    Handler.prototype[name] = function (event) {
      var x = event.zrX;
      var y = event.zrY;
      var isOutside = isOutsideBoundary(this, x, y);
      var hovered;
      var hoveredTarget;

      if (name !== 'mouseup' || !isOutside) {
        hovered = this.findHover(x, y);
        hoveredTarget = hovered.target;
      }

      if (name === 'mousedown') {
        this._downEl = hoveredTarget;
        this._downPoint = [event.zrX, event.zrY];
        this._upEl = hoveredTarget;
      } else if (name === 'mouseup') {
        this._upEl = hoveredTarget;
      } else if (name === 'click') {
        if (this._downEl !== this._upEl || !this._downPoint || dist(this._downPoint, [event.zrX, event.zrY]) > 4) {
          return;
        }

        this._downPoint = null;
      }

      this.dispatchToElement(hovered, name, event);
    };
  });

  function isHover(displayable, x, y) {
    if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {
      var el = displayable;
      var isSilent = void 0;

      while (el) {
        var clipPath = el.getClipPath();

        if (clipPath && !clipPath.contain(x, y)) {
          return false;
        }

        if (el.silent) {
          isSilent = true;
        }

        var hostEl = el.__hostTarget;
        el = hostEl ? hostEl : el.parent;
      }

      return isSilent ? SILENT : true;
    }

    return false;
  }

  function isOutsideBoundary(handlerInstance, x, y) {
    var painter = handlerInstance.painter;
    return x < 0 || x > painter.getWidth() || y < 0 || y > painter.getHeight();
  }

  var DEFAULT_MIN_MERGE = 32;
  var DEFAULT_MIN_GALLOPING = 7;

  function minRunLength(n) {
    var r = 0;

    while (n >= DEFAULT_MIN_MERGE) {
      r |= n & 1;
      n >>= 1;
    }

    return n + r;
  }

  function makeAscendingRun(array, lo, hi, compare) {
    var runHi = lo + 1;

    if (runHi === hi) {
      return 1;
    }

    if (compare(array[runHi++], array[lo]) < 0) {
      while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
        runHi++;
      }

      reverseRun(array, lo, runHi);
    } else {
      while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
        runHi++;
      }
    }

    return runHi - lo;
  }

  function reverseRun(array, lo, hi) {
    hi--;

    while (lo < hi) {
      var t = array[lo];
      array[lo++] = array[hi];
      array[hi--] = t;
    }
  }

  function binaryInsertionSort(array, lo, hi, start, compare) {
    if (start === lo) {
      start++;
    }

    for (; start < hi; start++) {
      var pivot = array[start];
      var left = lo;
      var right = start;
      var mid;

      while (left < right) {
        mid = left + right >>> 1;

        if (compare(pivot, array[mid]) < 0) {
          right = mid;
        } else {
          left = mid + 1;
        }
      }

      var n = start - left;

      switch (n) {
        case 3:
          array[left + 3] = array[left + 2];

        case 2:
          array[left + 2] = array[left + 1];

        case 1:
          array[left + 1] = array[left];
          break;

        default:
          while (n > 0) {
            array[left + n] = array[left + n - 1];
            n--;
          }

      }

      array[left] = pivot;
    }
  }

  function gallopLeft(value, array, start, length, hint, compare) {
    var lastOffset = 0;
    var maxOffset = 0;
    var offset = 1;

    if (compare(value, array[start + hint]) > 0) {
      maxOffset = length - hint;

      while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
        lastOffset = offset;
        offset = (offset << 1) + 1;

        if (offset <= 0) {
          offset = maxOffset;
        }
      }

      if (offset > maxOffset) {
        offset = maxOffset;
      }

      lastOffset += hint;
      offset += hint;
    } else {
      maxOffset = hint + 1;

      while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
        lastOffset = offset;
        offset = (offset << 1) + 1;

        if (offset <= 0) {
          offset = maxOffset;
        }
      }

      if (offset > maxOffset) {
        offset = maxOffset;
      }

      var tmp = lastOffset;
      lastOffset = hint - offset;
      offset = hint - tmp;
    }

    lastOffset++;

    while (lastOffset < offset) {
      var m = lastOffset + (offset - lastOffset >>> 1);

      if (compare(value, array[start + m]) > 0) {
        lastOffset = m + 1;
      } else {
        offset = m;
      }
    }

    return offset;
  }

  function gallopRight(value, array, start, length, hint, compare) {
    var lastOffset = 0;
    var maxOffset = 0;
    var offset = 1;

    if (compare(value, array[start + hint]) < 0) {
      maxOffset = hint + 1;

      while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
        lastOffset = offset;
        offset = (offset << 1) + 1;

        if (offset <= 0) {
          offset = maxOffset;
        }
      }

      if (offset > maxOffset) {
        offset = maxOffset;
      }

      var tmp = lastOffset;
      lastOffset = hint - offset;
      offset = hint - tmp;
    } else {
      maxOffset = length - hint;

      while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
        lastOffset = offset;
        offset = (offset << 1) + 1;

        if (offset <= 0) {
          offset = maxOffset;
        }
      }

      if (offset > maxOffset) {
        offset = maxOffset;
      }

      lastOffset += hint;
      offset += hint;
    }

    lastOffset++;

    while (lastOffset < offset) {
      var m = lastOffset + (offset - lastOffset >>> 1);

      if (compare(value, array[start + m]) < 0) {
        offset = m;
      } else {
        lastOffset = m + 1;
      }
    }

    return offset;
  }

  function TimSort(array, compare) {
    var minGallop = DEFAULT_MIN_GALLOPING;
    var length = 0;
    var runStart;
    var runLength;
    var stackSize = 0;
    length = array.length;
    var tmp = [];
    runStart = [];
    runLength = [];

    function pushRun(_runStart, _runLength) {
      runStart[stackSize] = _runStart;
      runLength[stackSize] = _runLength;
      stackSize += 1;
    }

    function mergeRuns() {
      while (stackSize > 1) {
        var n = stackSize - 2;

        if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) {
          if (runLength[n - 1] < runLength[n + 1]) {
            n--;
          }
        } else if (runLength[n] > runLength[n + 1]) {
          break;
        }

        mergeAt(n);
      }
    }

    function forceMergeRuns() {
      while (stackSize > 1) {
        var n = stackSize - 2;

        if (n > 0 && runLength[n - 1] < runLength[n + 1]) {
          n--;
        }

        mergeAt(n);
      }
    }

    function mergeAt(i) {
      var start1 = runStart[i];
      var length1 = runLength[i];
      var start2 = runStart[i + 1];
      var length2 = runLength[i + 1];
      runLength[i] = length1 + length2;

      if (i === stackSize - 3) {
        runStart[i + 1] = runStart[i + 2];
        runLength[i + 1] = runLength[i + 2];
      }

      stackSize--;
      var k = gallopRight(array[start2], array, start1, length1, 0, compare);
      start1 += k;
      length1 -= k;

      if (length1 === 0) {
        return;
      }

      length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);

      if (length2 === 0) {
        return;
      }

      if (length1 <= length2) {
        mergeLow(start1, length1, start2, length2);
      } else {
        mergeHigh(start1, length1, start2, length2);
      }
    }

    function mergeLow(start1, length1, start2, length2) {
      var i = 0;

      for (i = 0; i < length1; i++) {
        tmp[i] = array[start1 + i];
      }

      var cursor1 = 0;
      var cursor2 = start2;
      var dest = start1;
      array[dest++] = array[cursor2++];

      if (--length2 === 0) {
        for (i = 0; i < length1; i++) {
          array[dest + i] = tmp[cursor1 + i];
        }

        return;
      }

      if (length1 === 1) {
        for (i = 0; i < length2; i++) {
          array[dest + i] = array[cursor2 + i];
        }

        array[dest + length2] = tmp[cursor1];
        return;
      }

      var _minGallop = minGallop;
      var count1;
      var count2;
      var exit;

      while (1) {
        count1 = 0;
        count2 = 0;
        exit = false;

        do {
          if (compare(array[cursor2], tmp[cursor1]) < 0) {
            array[dest++] = array[cursor2++];
            count2++;
            count1 = 0;

            if (--length2 === 0) {
              exit = true;
              break;
            }
          } else {
            array[dest++] = tmp[cursor1++];
            count1++;
            count2 = 0;

            if (--length1 === 1) {
              exit = true;
              break;
            }
          }
        } while ((count1 | count2) < _minGallop);

        if (exit) {
          break;
        }

        do {
          count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);

          if (count1 !== 0) {
            for (i = 0; i < count1; i++) {
              array[dest + i] = tmp[cursor1 + i];
            }

            dest += count1;
            cursor1 += count1;
            length1 -= count1;

            if (length1 <= 1) {
              exit = true;
              break;
            }
          }

          array[dest++] = array[cursor2++];

          if (--length2 === 0) {
            exit = true;
            break;
          }

          count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);

          if (count2 !== 0) {
            for (i = 0; i < count2; i++) {
              array[dest + i] = array[cursor2 + i];
            }

            dest += count2;
            cursor2 += count2;
            length2 -= count2;

            if (length2 === 0) {
              exit = true;
              break;
            }
          }

          array[dest++] = tmp[cursor1++];

          if (--length1 === 1) {
            exit = true;
            break;
          }

          _minGallop--;
        } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);

        if (exit) {
          break;
        }

        if (_minGallop < 0) {
          _minGallop = 0;
        }

        _minGallop += 2;
      }

      minGallop = _minGallop;
      minGallop < 1 && (minGallop = 1);

      if (length1 === 1) {
        for (i = 0; i < length2; i++) {
          array[dest + i] = array[cursor2 + i];
        }

        array[dest + length2] = tmp[cursor1];
      } else if (length1 === 0) {
        throw new Error();
      } else {
        for (i = 0; i < length1; i++) {
          array[dest + i] = tmp[cursor1 + i];
        }
      }
    }

    function mergeHigh(start1, length1, start2, length2) {
      var i = 0;

      for (i = 0; i < length2; i++) {
        tmp[i] = array[start2 + i];
      }

      var cursor1 = start1 + length1 - 1;
      var cursor2 = length2 - 1;
      var dest = start2 + length2 - 1;
      var customCursor = 0;
      var customDest = 0;
      array[dest--] = array[cursor1--];

      if (--length1 === 0) {
        customCursor = dest - (length2 - 1);

        for (i = 0; i < length2; i++) {
          array[customCursor + i] = tmp[i];
        }

        return;
      }

      if (length2 === 1) {
        dest -= length1;
        cursor1 -= length1;
        customDest = dest + 1;
        customCursor = cursor1 + 1;

        for (i = length1 - 1; i >= 0; i--) {
          array[customDest + i] = array[customCursor + i];
        }

        array[dest] = tmp[cursor2];
        return;
      }

      var _minGallop = minGallop;

      while (true) {
        var count1 = 0;
        var count2 = 0;
        var exit = false;

        do {
          if (compare(tmp[cursor2], array[cursor1]) < 0) {
            array[dest--] = array[cursor1--];
            count1++;
            count2 = 0;

            if (--length1 === 0) {
              exit = true;
              break;
            }
          } else {
            array[dest--] = tmp[cursor2--];
            count2++;
            count1 = 0;

            if (--length2 === 1) {
              exit = true;
              break;
            }
          }
        } while ((count1 | count2) < _minGallop);

        if (exit) {
          break;
        }

        do {
          count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);

          if (count1 !== 0) {
            dest -= count1;
            cursor1 -= count1;
            length1 -= count1;
            customDest = dest + 1;
            customCursor = cursor1 + 1;

            for (i = count1 - 1; i >= 0; i--) {
              array[customDest + i] = array[customCursor + i];
            }

            if (length1 === 0) {
              exit = true;
              break;
            }
          }

          array[dest--] = tmp[cursor2--];

          if (--length2 === 1) {
            exit = true;
            break;
          }

          count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);

          if (count2 !== 0) {
            dest -= count2;
            cursor2 -= count2;
            length2 -= count2;
            customDest = dest + 1;
            customCursor = cursor2 + 1;

            for (i = 0; i < count2; i++) {
              array[customDest + i] = tmp[customCursor + i];
            }

            if (length2 <= 1) {
              exit = true;
              break;
            }
          }

          array[dest--] = array[cursor1--];

          if (--length1 === 0) {
            exit = true;
            break;
          }

          _minGallop--;
        } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);

        if (exit) {
          break;
        }

        if (_minGallop < 0) {
          _minGallop = 0;
        }

        _minGallop += 2;
      }

      minGallop = _minGallop;

      if (minGallop < 1) {
        minGallop = 1;
      }

      if (length2 === 1) {
        dest -= length1;
        cursor1 -= length1;
        customDest = dest + 1;
        customCursor = cursor1 + 1;

        for (i = length1 - 1; i >= 0; i--) {
          array[customDest + i] = array[customCursor + i];
        }

        array[dest] = tmp[cursor2];
      } else if (length2 === 0) {
        throw new Error();
      } else {
        customCursor = dest - (length2 - 1);

        for (i = 0; i < length2; i++) {
          array[customCursor + i] = tmp[i];
        }
      }
    }

    return {
      mergeRuns: mergeRuns,
      forceMergeRuns: forceMergeRuns,
      pushRun: pushRun
    };
  }

  function sort(array, compare, lo, hi) {
    if (!lo) {
      lo = 0;
    }

    if (!hi) {
      hi = array.length;
    }

    var remaining = hi - lo;

    if (remaining < 2) {
      return;
    }

    var runLength = 0;

    if (remaining < DEFAULT_MIN_MERGE) {
      runLength = makeAscendingRun(array, lo, hi, compare);
      binaryInsertionSort(array, lo, hi, lo + runLength, compare);
      return;
    }

    var ts = TimSort(array, compare);
    var minRun = minRunLength(remaining);

    do {
      runLength = makeAscendingRun(array, lo, hi, compare);

      if (runLength < minRun) {
        var force = remaining;

        if (force > minRun) {
          force = minRun;
        }

        binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
        runLength = force;
      }

      ts.pushRun(lo, runLength);
      ts.mergeRuns();
      remaining -= runLength;
      lo += runLength;
    } while (remaining !== 0);

    ts.forceMergeRuns();
  }

  var invalidZErrorLogged = false;

  function logInvalidZError() {
    if (invalidZErrorLogged) {
      return;
    }

    invalidZErrorLogged = true;
    console.warn('z / z2 / zlevel of displayable is invalid, which may cause unexpected errors');
  }

  function shapeCompareFunc(a, b) {
    if (a.zlevel === b.zlevel) {
      if (a.z === b.z) {
        return a.z2 - b.z2;
      }

      return a.z - b.z;
    }

    return a.zlevel - b.zlevel;
  }

  var Storage = function () {
    function Storage() {
      this._roots = [];
      this._displayList = [];
      this._displayListLen = 0;
      this.displayableSortFunc = shapeCompareFunc;
    }

    Storage.prototype.traverse = function (cb, context) {
      for (var i = 0; i < this._roots.length; i++) {
        this._roots[i].traverse(cb, context);
      }
    };

    Storage.prototype.getDisplayList = function (update, includeIgnore) {
      includeIgnore = includeIgnore || false;
      var displayList = this._displayList;

      if (update || !displayList.length) {
        this.updateDisplayList(includeIgnore);
      }

      return displayList;
    };

    Storage.prototype.updateDisplayList = function (includeIgnore) {
      this._displayListLen = 0;
      var roots = this._roots;
      var displayList = this._displayList;

      for (var i = 0, len = roots.length; i < len; i++) {
        this._updateAndAddDisplayable(roots[i], null, includeIgnore);
      }

      displayList.length = this._displayListLen;
      env.canvasSupported && sort(displayList, shapeCompareFunc);
    };

    Storage.prototype._updateAndAddDisplayable = function (el, clipPaths, includeIgnore) {
      if (el.ignore && !includeIgnore) {
        return;
      }

      el.beforeUpdate();

      if (el.__dirty) {
        el.update();
      }

      el.afterUpdate();
      var userSetClipPath = el.getClipPath();

      if (userSetClipPath) {
        if (clipPaths) {
          clipPaths = clipPaths.slice();
        } else {
          clipPaths = [];
        }

        var currentClipPath = userSetClipPath;
        var parentClipPath = el;

        while (currentClipPath) {
          currentClipPath.parent = parentClipPath;
          currentClipPath.updateTransform();
          clipPaths.push(currentClipPath);
          parentClipPath = currentClipPath;
          currentClipPath = currentClipPath.getClipPath();
        }
      }

      if (el.childrenRef) {
        var children = el.childrenRef();

        for (var i = 0; i < children.length; i++) {
          var child = children[i];

          if (el.__dirty) {
            child.markRedraw();
          }

          this._updateAndAddDisplayable(child, clipPaths, includeIgnore);
        }

        el.__dirty = 0;
      } else {
        var disp = el;

        if (clipPaths && clipPaths.length) {
          disp.__clipPaths = clipPaths;
        } else if (disp.__clipPaths && disp.__clipPaths.length > 0) {
          disp.__clipPaths = [];
        }

        if (isNaN(disp.z)) {
          logInvalidZError();
          disp.z = 0;
        }

        if (isNaN(disp.z2)) {
          logInvalidZError();
          disp.z2 = 0;
        }

        if (isNaN(disp.zlevel)) {
          logInvalidZError();
          disp.zlevel = 0;
        }

        this._displayList[this._displayListLen++] = disp;
      }

      var textGuide = el.getTextGuideLine();

      if (textGuide) {
        this._updateAndAddDisplayable(textGuide, clipPaths, includeIgnore);
      }

      var textEl = el.getTextContent();

      if (textEl) {
        this._updateAndAddDisplayable(textEl, clipPaths, includeIgnore);
      }
    };

    Storage.prototype.addRoot = function (el) {
      if (el.__zr && el.__zr.storage === this) {
        return;
      }

      this._roots.push(el);
    };

    Storage.prototype.delRoot = function (el) {
      if (el instanceof Array) {
        for (var i = 0, l = el.length; i < l; i++) {
          this.delRoot(el[i]);
        }

        return;
      }

      var idx = indexOf(this._roots, el);

      if (idx >= 0) {
        this._roots.splice(idx, 1);
      }
    };

    Storage.prototype.delAllRoots = function () {
      this._roots = [];
      this._displayList = [];
      this._displayListLen = 0;
      return;
    };

    Storage.prototype.getRoots = function () {
      return this._roots;
    };

    Storage.prototype.dispose = function () {
      this._displayList = null;
      this._roots = null;
    };

    return Storage;
  }();

  var requestAnimationFrame;

  requestAnimationFrame = typeof window !== 'undefined' && window.requestAnimationFrame && window.requestAnimationFrame.bind(window) || window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window) || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || function (func) {
    return setTimeout(func, 16);
  };

  var requestAnimationFrame$1 = requestAnimationFrame;
  var easing = {
    linear: function (k) {
      return k;
    },
    quadraticIn: function (k) {
      return k * k;
    },
    quadraticOut: function (k) {
      return k * (2 - k);
    },
    quadraticInOut: function (k) {
      if ((k *= 2) < 1) {
        return 0.5 * k * k;
      }

      return -0.5 * (--k * (k - 2) - 1);
    },
    cubicIn: function (k) {
      return k * k * k;
    },
    cubicOut: function (k) {
      return --k * k * k + 1;
    },
    cubicInOut: function (k) {
      if ((k *= 2) < 1) {
        return 0.5 * k * k * k;
      }

      return 0.5 * ((k -= 2) * k * k + 2);
    },
    quarticIn: function (k) {
      return k * k * k * k;
    },
    quarticOut: function (k) {
      return 1 - --k * k * k * k;
    },
    quarticInOut: function (k) {
      if ((k *= 2) < 1) {
        return 0.5 * k * k * k * k;
      }

      return -0.5 * ((k -= 2) * k * k * k - 2);
    },
    quinticIn: function (k) {
      return k * k * k * k * k;
    },
    quinticOut: function (k) {
      return --k * k * k * k * k + 1;
    },
    quinticInOut: function (k) {
      if ((k *= 2) < 1) {
        return 0.5 * k * k * k * k * k;
      }

      return 0.5 * ((k -= 2) * k * k * k * k + 2);
    },
    sinusoidalIn: function (k) {
      return 1 - Math.cos(k * Math.PI / 2);
    },
    sinusoidalOut: function (k) {
      return Math.sin(k * Math.PI / 2);
    },
    sinusoidalInOut: function (k) {
      return 0.5 * (1 - Math.cos(Math.PI * k));
    },
    exponentialIn: function (k) {
      return k === 0 ? 0 : Math.pow(1024, k - 1);
    },
    exponentialOut: function (k) {
      return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);
    },
    exponentialInOut: function (k) {
      if (k === 0) {
        return 0;
      }

      if (k === 1) {
        return 1;
      }

      if ((k *= 2) < 1) {
        return 0.5 * Math.pow(1024, k - 1);
      }

      return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);
    },
    circularIn: function (k) {
      return 1 - Math.sqrt(1 - k * k);
    },
    circularOut: function (k) {
      return Math.sqrt(1 - --k * k);
    },
    circularInOut: function (k) {
      if ((k *= 2) < 1) {
        return -0.5 * (Math.sqrt(1 - k * k) - 1);
      }

      return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);
    },
    elasticIn: function (k) {
      var s;
      var a = 0.1;
      var p = 0.4;

      if (k === 0) {
        return 0;
      }

      if (k === 1) {
        return 1;
      }

      if (!a || a < 1) {
        a = 1;
        s = p / 4;
      } else {
        s = p * Math.asin(1 / a) / (2 * Math.PI);
      }

      return -(a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p));
    },
    elasticOut: function (k) {
      var s;
      var a = 0.1;
      var p = 0.4;

      if (k === 0) {
        return 0;
      }

      if (k === 1) {
        return 1;
      }

      if (!a || a < 1) {
        a = 1;
        s = p / 4;
      } else {
        s = p * Math.asin(1 / a) / (2 * Math.PI);
      }

      return a * Math.pow(2, -10 * k) * Math.sin((k - s) * (2 * Math.PI) / p) + 1;
    },
    elasticInOut: function (k) {
      var s;
      var a = 0.1;
      var p = 0.4;

      if (k === 0) {
        return 0;
      }

      if (k === 1) {
        return 1;
      }

      if (!a || a < 1) {
        a = 1;
        s = p / 4;
      } else {
        s = p * Math.asin(1 / a) / (2 * Math.PI);
      }

      if ((k *= 2) < 1) {
        return -0.5 * (a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p));
      }

      return a * Math.pow(2, -10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;
    },
    backIn: function (k) {
      var s = 1.70158;
      return k * k * ((s + 1) * k - s);
    },
    backOut: function (k) {
      var s = 1.70158;
      return --k * k * ((s + 1) * k + s) + 1;
    },
    backInOut: function (k) {
      var s = 1.70158 * 1.525;

      if ((k *= 2) < 1) {
        return 0.5 * (k * k * ((s + 1) * k - s));
      }

      return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);
    },
    bounceIn: function (k) {
      return 1 - easing.bounceOut(1 - k);
    },
    bounceOut: function (k) {
      if (k < 1 / 2.75) {
        return 7.5625 * k * k;
      } else if (k < 2 / 2.75) {
        return 7.5625 * (k -= 1.5 / 2.75) * k + 0.75;
      } else if (k < 2.5 / 2.75) {
        return 7.5625 * (k -= 2.25 / 2.75) * k + 0.9375;
      } else {
        return 7.5625 * (k -= 2.625 / 2.75) * k + 0.984375;
      }
    },
    bounceInOut: function (k) {
      if (k < 0.5) {
        return easing.bounceIn(k * 2) * 0.5;
      }

      return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;
    }
  };

  var Clip = function () {
    function Clip(opts) {
      this._initialized = false;
      this._startTime = 0;
      this._pausedTime = 0;
      this._paused = false;
      this._life = opts.life || 1000;
      this._delay = opts.delay || 0;
      this.loop = opts.loop == null ? false : opts.loop;
      this.gap = opts.gap || 0;
      this.easing = opts.easing || 'linear';
      this.onframe = opts.onframe;
      this.ondestroy = opts.ondestroy;
      this.onrestart = opts.onrestart;
    }

    Clip.prototype.step = function (globalTime, deltaTime) {
      if (!this._initialized) {
        this._startTime = globalTime + this._delay;
        this._initialized = true;
      }

      if (this._paused) {
        this._pausedTime += deltaTime;
        return;
      }

      var percent = (globalTime - this._startTime - this._pausedTime) / this._life;

      if (percent < 0) {
        percent = 0;
      }

      percent = Math.min(percent, 1);
      var easing$1 = this.easing;
      var easingFunc = typeof easing$1 === 'string' ? easing[easing$1] : easing$1;
      var schedule = typeof easingFunc === 'function' ? easingFunc(percent) : percent;
      this.onframe && this.onframe(schedule);

      if (percent === 1) {
        if (this.loop) {
          this._restart(globalTime);

          this.onrestart && this.onrestart();
        } else {
          return true;
        }
      }

      return false;
    };

    Clip.prototype._restart = function (globalTime) {
      var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;
      this._startTime = globalTime - remainder + this.gap;
      this._pausedTime = 0;
    };

    Clip.prototype.pause = function () {
      this._paused = true;
    };

    Clip.prototype.resume = function () {
      this._paused = false;
    };

    return Clip;
  }();

  var Entry = function () {
    function Entry(val) {
      this.value = val;
    }

    return Entry;
  }();

  var LinkedList = function () {
    function LinkedList() {
      this._len = 0;
    }

    LinkedList.prototype.insert = function (val) {
      var entry = new Entry(val);
      this.insertEntry(entry);
      return entry;
    };

    LinkedList.prototype.insertEntry = function (entry) {
      if (!this.head) {
        this.head = this.tail = entry;
      } else {
        this.tail.next = entry;
        entry.prev = this.tail;
        entry.next = null;
        this.tail = entry;
      }

      this._len++;
    };

    LinkedList.prototype.remove = function (entry) {
      var prev = entry.prev;
      var next = entry.next;

      if (prev) {
        prev.next = next;
      } else {
        this.head = next;
      }

      if (next) {
        next.prev = prev;
      } else {
        this.tail = prev;
      }

      entry.next = entry.prev = null;
      this._len--;
    };

    LinkedList.prototype.len = function () {
      return this._len;
    };

    LinkedList.prototype.clear = function () {
      this.head = this.tail = null;
      this._len = 0;
    };

    return LinkedList;
  }();

  var LRU = function () {
    function LRU(maxSize) {
      this._list = new LinkedList();
      this._maxSize = 10;
      this._map = {};
      this._maxSize = maxSize;
    }

    LRU.prototype.put = function (key, value) {
      var list = this._list;
      var map = this._map;
      var removed = null;

      if (map[key] == null) {
        var len = list.len();
        var entry = this._lastRemovedEntry;

        if (len >= this._maxSize && len > 0) {
          var leastUsedEntry = list.head;
          list.remove(leastUsedEntry);
          delete map[leastUsedEntry.key];
          removed = leastUsedEntry.value;
          this._lastRemovedEntry = leastUsedEntry;
        }

        if (entry) {
          entry.value = value;
        } else {
          entry = new Entry(value);
        }

        entry.key = key;
        list.insertEntry(entry);
        map[key] = entry;
      }

      return removed;
    };

    LRU.prototype.get = function (key) {
      var entry = this._map[key];
      var list = this._list;

      if (entry != null) {
        if (entry !== list.tail) {
          list.remove(entry);
          list.insertEntry(entry);
        }

        return entry.value;
      }
    };

    LRU.prototype.clear = function () {
      this._list.clear();

      this._map = {};
    };

    LRU.prototype.len = function () {
      return this._list.len();
    };

    return LRU;
  }();

  var kCSSColorTable = {
    'transparent': [0, 0, 0, 0],
    'aliceblue': [240, 248, 255, 1],
    'antiquewhite': [250, 235, 215, 1],
    'aqua': [0, 255, 255, 1],
    'aquamarine': [127, 255, 212, 1],
    'azure': [240, 255, 255, 1],
    'beige': [245, 245, 220, 1],
    'bisque': [255, 228, 196, 1],
    'black': [0, 0, 0, 1],
    'blanchedalmond': [255, 235, 205, 1],
    'blue': [0, 0, 255, 1],
    'blueviolet': [138, 43, 226, 1],
    'brown': [165, 42, 42, 1],
    'burlywood': [222, 184, 135, 1],
    'cadetblue': [95, 158, 160, 1],
    'chartreuse': [127, 255, 0, 1],
    'chocolate': [210, 105, 30, 1],
    'coral': [255, 127, 80, 1],
    'cornflowerblue': [100, 149, 237, 1],
    'cornsilk': [255, 248, 220, 1],
    'crimson': [220, 20, 60, 1],
    'cyan': [0, 255, 255, 1],
    'darkblue': [0, 0, 139, 1],
    'darkcyan': [0, 139, 139, 1],
    'darkgoldenrod': [184, 134, 11, 1],
    'darkgray': [169, 169, 169, 1],
    'darkgreen': [0, 100, 0, 1],
    'darkgrey': [169, 169, 169, 1],
    'darkkhaki': [189, 183, 107, 1],
    'darkmagenta': [139, 0, 139, 1],
    'darkolivegreen': [85, 107, 47, 1],
    'darkorange': [255, 140, 0, 1],
    'darkorchid': [153, 50, 204, 1],
    'darkred': [139, 0, 0, 1],
    'darksalmon': [233, 150, 122, 1],
    'darkseagreen': [143, 188, 143, 1],
    'darkslateblue': [72, 61, 139, 1],
    'darkslategray': [47, 79, 79, 1],
    'darkslategrey': [47, 79, 79, 1],
    'darkturquoise': [0, 206, 209, 1],
    'darkviolet': [148, 0, 211, 1],
    'deeppink': [255, 20, 147, 1],
    'deepskyblue': [0, 191, 255, 1],
    'dimgray': [105, 105, 105, 1],
    'dimgrey': [105, 105, 105, 1],
    'dodgerblue': [30, 144, 255, 1],
    'firebrick': [178, 34, 34, 1],
    'floralwhite': [255, 250, 240, 1],
    'forestgreen': [34, 139, 34, 1],
    'fuchsia': [255, 0, 255, 1],
    'gainsboro': [220, 220, 220, 1],
    'ghostwhite': [248, 248, 255, 1],
    'gold': [255, 215, 0, 1],
    'goldenrod': [218, 165, 32, 1],
    'gray': [128, 128, 128, 1],
    'green': [0, 128, 0, 1],
    'greenyellow': [173, 255, 47, 1],
    'grey': [128, 128, 128, 1],
    'honeydew': [240, 255, 240, 1],
    'hotpink': [255, 105, 180, 1],
    'indianred': [205, 92, 92, 1],
    'indigo': [75, 0, 130, 1],
    'ivory': [255, 255, 240, 1],
    'khaki': [240, 230, 140, 1],
    'lavender': [230, 230, 250, 1],
    'lavenderblush': [255, 240, 245, 1],
    'lawngreen': [124, 252, 0, 1],
    'lemonchiffon': [255, 250, 205, 1],
    'lightblue': [173, 216, 230, 1],
    'lightcoral': [240, 128, 128, 1],
    'lightcyan': [224, 255, 255, 1],
    'lightgoldenrodyellow': [250, 250, 210, 1],
    'lightgray': [211, 211, 211, 1],
    'lightgreen': [144, 238, 144, 1],
    'lightgrey': [211, 211, 211, 1],
    'lightpink': [255, 182, 193, 1],
    'lightsalmon': [255, 160, 122, 1],
    'lightseagreen': [32, 178, 170, 1],
    'lightskyblue': [135, 206, 250, 1],
    'lightslategray': [119, 136, 153, 1],
    'lightslategrey': [119, 136, 153, 1],
    'lightsteelblue': [176, 196, 222, 1],
    'lightyellow': [255, 255, 224, 1],
    'lime': [0, 255, 0, 1],
    'limegreen': [50, 205, 50, 1],
    'linen': [250, 240, 230, 1],
    'magenta': [255, 0, 255, 1],
    'maroon': [128, 0, 0, 1],
    'mediumaquamarine': [102, 205, 170, 1],
    'mediumblue': [0, 0, 205, 1],
    'mediumorchid': [186, 85, 211, 1],
    'mediumpurple': [147, 112, 219, 1],
    'mediumseagreen': [60, 179, 113, 1],
    'mediumslateblue': [123, 104, 238, 1],
    'mediumspringgreen': [0, 250, 154, 1],
    'mediumturquoise': [72, 209, 204, 1],
    'mediumvioletred': [199, 21, 133, 1],
    'midnightblue': [25, 25, 112, 1],
    'mintcream': [245, 255, 250, 1],
    'mistyrose': [255, 228, 225, 1],
    'moccasin': [255, 228, 181, 1],
    'navajowhite': [255, 222, 173, 1],
    'navy': [0, 0, 128, 1],
    'oldlace': [253, 245, 230, 1],
    'olive': [128, 128, 0, 1],
    'olivedrab': [107, 142, 35, 1],
    'orange': [255, 165, 0, 1],
    'orangered': [255, 69, 0, 1],
    'orchid': [218, 112, 214, 1],
    'palegoldenrod': [238, 232, 170, 1],
    'palegreen': [152, 251, 152, 1],
    'paleturquoise': [175, 238, 238, 1],
    'palevioletred': [219, 112, 147, 1],
    'papayawhip': [255, 239, 213, 1],
    'peachpuff': [255, 218, 185, 1],
    'peru': [205, 133, 63, 1],
    'pink': [255, 192, 203, 1],
    'plum': [221, 160, 221, 1],
    'powderblue': [176, 224, 230, 1],
    'purple': [128, 0, 128, 1],
    'red': [255, 0, 0, 1],
    'rosybrown': [188, 143, 143, 1],
    'royalblue': [65, 105, 225, 1],
    'saddlebrown': [139, 69, 19, 1],
    'salmon': [250, 128, 114, 1],
    'sandybrown': [244, 164, 96, 1],
    'seagreen': [46, 139, 87, 1],
    'seashell': [255, 245, 238, 1],
    'sienna': [160, 82, 45, 1],
    'silver': [192, 192, 192, 1],
    'skyblue': [135, 206, 235, 1],
    'slateblue': [106, 90, 205, 1],
    'slategray': [112, 128, 144, 1],
    'slategrey': [112, 128, 144, 1],
    'snow': [255, 250, 250, 1],
    'springgreen': [0, 255, 127, 1],
    'steelblue': [70, 130, 180, 1],
    'tan': [210, 180, 140, 1],
    'teal': [0, 128, 128, 1],
    'thistle': [216, 191, 216, 1],
    'tomato': [255, 99, 71, 1],
    'turquoise': [64, 224, 208, 1],
    'violet': [238, 130, 238, 1],
    'wheat': [245, 222, 179, 1],
    'white': [255, 255, 255, 1],
    'whitesmoke': [245, 245, 245, 1],
    'yellow': [255, 255, 0, 1],
    'yellowgreen': [154, 205, 50, 1]
  };

  function clampCssByte(i) {
    i = Math.round(i);
    return i < 0 ? 0 : i > 255 ? 255 : i;
  }

  function clampCssFloat(f) {
    return f < 0 ? 0 : f > 1 ? 1 : f;
  }

  function parseCssInt(val) {
    var str = val;

    if (str.length && str.charAt(str.length - 1) === '%') {
      return clampCssByte(parseFloat(str) / 100 * 255);
    }

    return clampCssByte(parseInt(str, 10));
  }

  function parseCssFloat(val) {
    var str = val;

    if (str.length && str.charAt(str.length - 1) === '%') {
      return clampCssFloat(parseFloat(str) / 100);
    }

    return clampCssFloat(parseFloat(str));
  }

  function cssHueToRgb(m1, m2, h) {
    if (h < 0) {
      h += 1;
    } else if (h > 1) {
      h -= 1;
    }

    if (h * 6 < 1) {
      return m1 + (m2 - m1) * h * 6;
    }

    if (h * 2 < 1) {
      return m2;
    }

    if (h * 3 < 2) {
      return m1 + (m2 - m1) * (2 / 3 - h) * 6;
    }

    return m1;
  }

  function setRgba(out, r, g, b, a) {
    out[0] = r;
    out[1] = g;
    out[2] = b;
    out[3] = a;
    return out;
  }

  function copyRgba(out, a) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    return out;
  }

  var colorCache = new LRU(20);
  var lastRemovedArr = null;

  function putToCache(colorStr, rgbaArr) {
    if (lastRemovedArr) {
      copyRgba(lastRemovedArr, rgbaArr);
    }

    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || rgbaArr.slice());
  }

  function parse(colorStr, rgbaArr) {
    if (!colorStr) {
      return;
    }

    rgbaArr = rgbaArr || [];
    var cached = colorCache.get(colorStr);

    if (cached) {
      return copyRgba(rgbaArr, cached);
    }

    colorStr = colorStr + '';
    var str = colorStr.replace(/ /g, '').toLowerCase();

    if (str in kCSSColorTable) {
      copyRgba(rgbaArr, kCSSColorTable[str]);
      putToCache(colorStr, rgbaArr);
      return rgbaArr;
    }

    if (str.charAt(0) === '#') {
      if (str.length === 4) {
        var iv = parseInt(str.substr(1), 16);

        if (!(iv >= 0 && iv <= 0xfff)) {
          setRgba(rgbaArr, 0, 0, 0, 1);
          return;
        }

        setRgba(rgbaArr, (iv & 0xf00) >> 4 | (iv & 0xf00) >> 8, iv & 0xf0 | (iv & 0xf0) >> 4, iv & 0xf | (iv & 0xf) << 4, 1);
        putToCache(colorStr, rgbaArr);
        return rgbaArr;
      } else if (str.length === 7) {
        var iv = parseInt(str.substr(1), 16);

        if (!(iv >= 0 && iv <= 0xffffff)) {
          setRgba(rgbaArr, 0, 0, 0, 1);
          return;
        }

        setRgba(rgbaArr, (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, 1);
        putToCache(colorStr, rgbaArr);
        return rgbaArr;
      }

      return;
    }

    var op = str.indexOf('(');
    var ep = str.indexOf(')');

    if (op !== -1 && ep + 1 === str.length) {
      var fname = str.substr(0, op);
      var params = str.substr(op + 1, ep - (op + 1)).split(',');
      var alpha = 1;

      switch (fname) {
        case 'rgba':
          if (params.length !== 4) {
            setRgba(rgbaArr, 0, 0, 0, 1);
            return;
          }

          alpha = parseCssFloat(params.pop());

        case 'rgb':
          if (params.length !== 3) {
            setRgba(rgbaArr, 0, 0, 0, 1);
            return;
          }

          setRgba(rgbaArr, parseCssInt(params[0]), parseCssInt(params[1]), parseCssInt(params[2]), alpha);
          putToCache(colorStr, rgbaArr);
          return rgbaArr;

        case 'hsla':
          if (params.length !== 4) {
            setRgba(rgbaArr, 0, 0, 0, 1);
            return;
          }

          params[3] = parseCssFloat(params[3]);
          hsla2rgba(params, rgbaArr);
          putToCache(colorStr, rgbaArr);
          return rgbaArr;

        case 'hsl':
          if (params.length !== 3) {
            setRgba(rgbaArr, 0, 0, 0, 1);
            return;
          }

          hsla2rgba(params, rgbaArr);
          putToCache(colorStr, rgbaArr);
          return rgbaArr;

        default:
          return;
      }
    }

    setRgba(rgbaArr, 0, 0, 0, 1);
    return;
  }

  function hsla2rgba(hsla, rgba) {
    var h = (parseFloat(hsla[0]) % 360 + 360) % 360 / 360;
    var s = parseCssFloat(hsla[1]);
    var l = parseCssFloat(hsla[2]);
    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
    var m1 = l * 2 - m2;
    rgba = rgba || [];
    setRgba(rgba, clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255), clampCssByte(cssHueToRgb(m1, m2, h) * 255), clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255), 1);

    if (hsla.length === 4) {
      rgba[3] = hsla[3];
    }

    return rgba;
  }

  function lift(color, level) {
    var colorArr = parse(color);

    if (colorArr) {
      for (var i = 0; i < 3; i++) {
        if (level < 0) {
          colorArr[i] = colorArr[i] * (1 - level) | 0;
        } else {
          colorArr[i] = (255 - colorArr[i]) * level + colorArr[i] | 0;
        }

        if (colorArr[i] > 255) {
          colorArr[i] = 255;
        } else if (colorArr[i] < 0) {
          colorArr[i] = 0;
        }
      }

      return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');
    }
  }

  function stringify(arrColor, type) {
    if (!arrColor || !arrColor.length) {
      return;
    }

    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];

    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {
      colorStr += ',' + arrColor[3];
    }

    return type + '(' + colorStr + ')';
  }

  function lum(color, backgroundLum) {
    var arr = parse(color);
    return arr ? (0.299 * arr[0] + 0.587 * arr[1] + 0.114 * arr[2]) * arr[3] / 255 + (1 - arr[3]) * backgroundLum : 0;
  }

  var arraySlice = Array.prototype.slice;

  function interpolateNumber(p0, p1, percent) {
    return (p1 - p0) * percent + p0;
  }

  function step(p0, p1, percent) {
    return percent > 0.5 ? p1 : p0;
  }

  function interpolate1DArray(out, p0, p1, percent) {
    var len = p0.length;

    for (var i = 0; i < len; i++) {
      out[i] = interpolateNumber(p0[i], p1[i], percent);
    }
  }

  function interpolate2DArray(out, p0, p1, percent) {
    var len = p0.length;
    var len2 = len && p0[0].length;

    for (var i = 0; i < len; i++) {
      if (!out[i]) {
        out[i] = [];
      }

      for (var j = 0; j < len2; j++) {
        out[i][j] = interpolateNumber(p0[i][j], p1[i][j], percent);
      }
    }
  }

  function add1DArray(out, p0, p1, sign) {
    var len = p0.length;

    for (var i = 0; i < len; i++) {
      out[i] = p0[i] + p1[i] * sign;
    }

    return out;
  }

  function add2DArray(out, p0, p1, sign) {
    var len = p0.length;
    var len2 = len && p0[0].length;

    for (var i = 0; i < len; i++) {
      if (!out[i]) {
        out[i] = [];
      }

      for (var j = 0; j < len2; j++) {
        out[i][j] = p0[i][j] + p1[i][j] * sign;
      }
    }

    return out;
  }

  function fillArray(val0, val1, arrDim) {
    var arr0 = val0;
    var arr1 = val1;

    if (!arr0.push || !arr1.push) {
      return;
    }

    var arr0Len = arr0.length;
    var arr1Len = arr1.length;

    if (arr0Len !== arr1Len) {
      var isPreviousLarger = arr0Len > arr1Len;

      if (isPreviousLarger) {
        arr0.length = arr1Len;
      } else {
        for (var i = arr0Len; i < arr1Len; i++) {
          arr0.push(arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i]));
        }
      }
    }

    var len2 = arr0[0] && arr0[0].length;

    for (var i = 0; i < arr0.length; i++) {
      if (arrDim === 1) {
        if (isNaN(arr0[i])) {
          arr0[i] = arr1[i];
        }
      } else {
        for (var j = 0; j < len2; j++) {
          if (isNaN(arr0[i][j])) {
            arr0[i][j] = arr1[i][j];
          }
        }
      }
    }
  }

  function is1DArraySame(arr0, arr1) {
    var len = arr0.length;

    if (len !== arr1.length) {
      return false;
    }

    for (var i = 0; i < len; i++) {
      if (arr0[i] !== arr1[i]) {
        return false;
      }
    }

    return true;
  }

  function catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {
    var v0 = (p2 - p0) * 0.5;
    var v1 = (p3 - p1) * 0.5;
    return (2 * (p1 - p2) + v0 + v1) * t3 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2 + v0 * t + p1;
  }

  function catmullRomInterpolate1DArray(out, p0, p1, p2, p3, t, t2, t3) {
    var len = p0.length;

    for (var i = 0; i < len; i++) {
      out[i] = catmullRomInterpolate(p0[i], p1[i], p2[i], p3[i], t, t2, t3);
    }
  }

  function catmullRomInterpolate2DArray(out, p0, p1, p2, p3, t, t2, t3) {
    var len = p0.length;
    var len2 = p0[0].length;

    for (var i = 0; i < len; i++) {
      if (!out[i]) {
        out[1] = [];
      }

      for (var j = 0; j < len2; j++) {
        out[i][j] = catmullRomInterpolate(p0[i][j], p1[i][j], p2[i][j], p3[i][j], t, t2, t3);
      }
    }
  }

  function cloneValue(value) {
    if (isArrayLike(value)) {
      var len = value.length;

      if (isArrayLike(value[0])) {
        var ret = [];

        for (var i = 0; i < len; i++) {
          ret.push(arraySlice.call(value[i]));
        }

        return ret;
      }

      return arraySlice.call(value);
    }

    return value;
  }

  function rgba2String(rgba) {
    rgba[0] = Math.floor(rgba[0]);
    rgba[1] = Math.floor(rgba[1]);
    rgba[2] = Math.floor(rgba[2]);
    return 'rgba(' + rgba.join(',') + ')';
  }

  function guessArrayDim(value) {
    return isArrayLike(value && value[0]) ? 2 : 1;
  }

  var tmpRgba = [0, 0, 0, 0];

  var Track = function () {
    function Track(propName) {
      this.keyframes = [];
      this.maxTime = 0;
      this.arrDim = 0;
      this.interpolable = true;
      this._needsSort = false;
      this._isAllValueEqual = true;
      this._lastFrame = 0;
      this._lastFramePercent = 0;
      this.propName = propName;
    }

    Track.prototype.isFinished = function () {
      return this._finished;
    };

    Track.prototype.setFinished = function () {
      this._finished = true;
    };

    Track.prototype.needsAnimate = function () {
      return !this._isAllValueEqual && this.keyframes.length >= 2 && this.interpolable;
    };

    Track.prototype.getAdditiveTrack = function () {
      return this._additiveTrack;
    };

    Track.prototype.addKeyframe = function (time, value) {
      if (time >= this.maxTime) {
        this.maxTime = time;
      } else {
        this._needsSort = true;
      }

      var keyframes = this.keyframes;
      var len = keyframes.length;

      if (this.interpolable) {
        if (isArrayLike(value)) {
          var arrayDim = guessArrayDim(value);

          if (len > 0 && this.arrDim !== arrayDim) {
            this.interpolable = false;
            return;
          }

          if (arrayDim === 1 && typeof value[0] !== 'number' || arrayDim === 2 && typeof value[0][0] !== 'number') {
            this.interpolable = false;
            return;
          }

          if (len > 0) {
            var lastFrame = keyframes[len - 1];

            if (this._isAllValueEqual) {
              if (arrayDim === 1) {
                if (!is1DArraySame(value, lastFrame.value)) {
                  this._isAllValueEqual = false;
                }
              } else {
                this._isAllValueEqual = false;
              }
            }
          }

          this.arrDim = arrayDim;
        } else {
          if (this.arrDim > 0) {
            this.interpolable = false;
            return;
          }

          if (typeof value === 'string') {
            var colorArray = parse(value);

            if (colorArray) {
              value = colorArray;
              this.isValueColor = true;
            } else {
              this.interpolable = false;
            }
          } else if (typeof value !== 'number') {
            this.interpolable = false;
            return;
          }

          if (this._isAllValueEqual && len > 0) {
            var lastFrame = keyframes[len - 1];

            if (this.isValueColor && !is1DArraySame(lastFrame.value, value)) {
              this._isAllValueEqual = false;
            } else if (lastFrame.value !== value) {
              this._isAllValueEqual = false;
            }
          }
        }
      }

      var kf = {
        time: time,
        value: value,
        percent: 0
      };
      this.keyframes.push(kf);
      return kf;
    };

    Track.prototype.prepare = function (additiveTrack) {
      var kfs = this.keyframes;

      if (this._needsSort) {
        kfs.sort(function (a, b) {
          return a.time - b.time;
        });
      }

      var arrDim = this.arrDim;
      var kfsLen = kfs.length;
      var lastKf = kfs[kfsLen - 1];

      for (var i = 0; i < kfsLen; i++) {
        kfs[i].percent = kfs[i].time / this.maxTime;

        if (arrDim > 0 && i !== kfsLen - 1) {
          fillArray(kfs[i].value, lastKf.value, arrDim);
        }
      }

      if (additiveTrack && this.interpolable && arrDim === additiveTrack.arrDim && this.isValueColor === additiveTrack.isValueColor && !additiveTrack._finished) {
        this._additiveTrack = additiveTrack;
        var startValue = kfs[0].value;

        for (var i = 0; i < kfsLen; i++) {
          if (arrDim === 0) {
            if (this.isValueColor) {
              kfs[i].additiveValue = add1DArray([], kfs[i].value, startValue, -1);
            } else {
              kfs[i].additiveValue = kfs[i].value - startValue;
            }
          } else if (arrDim === 1) {
            kfs[i].additiveValue = add1DArray([], kfs[i].value, startValue, -1);
          } else if (arrDim === 2) {
            kfs[i].additiveValue = add2DArray([], kfs[i].value, startValue, -1);
          }
        }
      }
    };

    Track.prototype.step = function (target, percent) {
      if (this._finished) {
        return;
      }

      if (this._additiveTrack && this._additiveTrack._finished) {
        this._additiveTrack = null;
      }

      var isAdditive = this._additiveTrack != null;
      var valueKey = isAdditive ? 'additiveValue' : 'value';
      var keyframes = this.keyframes;
      var kfsNum = this.keyframes.length;
      var propName = this.propName;
      var arrDim = this.arrDim;
      var isValueColor = this.isValueColor;
      var frameIdx;

      if (percent < 0) {
        frameIdx = 0;
      } else if (percent < this._lastFramePercent) {
        var start = Math.min(this._lastFrame + 1, kfsNum - 1);

        for (frameIdx = start; frameIdx >= 0; frameIdx--) {
          if (keyframes[frameIdx].percent <= percent) {
            break;
          }
        }

        frameIdx = Math.min(frameIdx, kfsNum - 2);
      } else {
        for (frameIdx = this._lastFrame; frameIdx < kfsNum; frameIdx++) {
          if (keyframes[frameIdx].percent > percent) {
            break;
          }
        }

        frameIdx = Math.min(frameIdx - 1, kfsNum - 2);
      }

      var nextFrame = keyframes[frameIdx + 1];
      var frame = keyframes[frameIdx];

      if (!(frame && nextFrame)) {
        return;
      }

      this._lastFrame = frameIdx;
      this._lastFramePercent = percent;
      var range = nextFrame.percent - frame.percent;

      if (range === 0) {
        return;
      }

      var w = (percent - frame.percent) / range;
      var targetArr = isAdditive ? this._additiveValue : isValueColor ? tmpRgba : target[propName];

      if ((arrDim > 0 || isValueColor) && !targetArr) {
        targetArr = this._additiveValue = [];
      }

      if (this.useSpline) {
        var p1 = keyframes[frameIdx][valueKey];
        var p0 = keyframes[frameIdx === 0 ? frameIdx : frameIdx - 1][valueKey];
        var p2 = keyframes[frameIdx > kfsNum - 2 ? kfsNum - 1 : frameIdx + 1][valueKey];
        var p3 = keyframes[frameIdx > kfsNum - 3 ? kfsNum - 1 : frameIdx + 2][valueKey];

        if (arrDim > 0) {
          arrDim === 1 ? catmullRomInterpolate1DArray(targetArr, p0, p1, p2, p3, w, w * w, w * w * w) : catmullRomInterpolate2DArray(targetArr, p0, p1, p2, p3, w, w * w, w * w * w);
        } else if (isValueColor) {
          catmullRomInterpolate1DArray(targetArr, p0, p1, p2, p3, w, w * w, w * w * w);

          if (!isAdditive) {
            target[propName] = rgba2String(targetArr);
          }
        } else {
          var value = void 0;

          if (!this.interpolable) {
            value = p2;
          } else {
            value = catmullRomInterpolate(p0, p1, p2, p3, w, w * w, w * w * w);
          }

          if (isAdditive) {
            this._additiveValue = value;
          } else {
            target[propName] = value;
          }
        }
      } else {
        if (arrDim > 0) {
          arrDim === 1 ? interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w) : interpolate2DArray(targetArr, frame[valueKey], nextFrame[valueKey], w);
        } else if (isValueColor) {
          interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w);

          if (!isAdditive) {
            target[propName] = rgba2String(targetArr);
          }
        } else {
          var value = void 0;

          if (!this.interpolable) {
            value = step(frame[valueKey], nextFrame[valueKey], w);
          } else {
            value = interpolateNumber(frame[valueKey], nextFrame[valueKey], w);
          }

          if (isAdditive) {
            this._additiveValue = value;
          } else {
            target[propName] = value;
          }
        }
      }

      if (isAdditive) {
        this._addToTarget(target);
      }
    };

    Track.prototype._addToTarget = function (target) {
      var arrDim = this.arrDim;
      var propName = this.propName;

      if (arrDim === 0) {
        if (this.isValueColor) {
          parse(target[propName], tmpRgba);
          add1DArray(tmpRgba, tmpRgba, this._additiveValue, 1);
          target[propName] = rgba2String(tmpRgba);
        } else {
          target[propName] = target[propName] + this._additiveValue;
        }
      } else if (arrDim === 1) {
        add1DArray(target[propName], target[propName], this._additiveValue, 1);
      } else if (arrDim === 2) {
        add2DArray(target[propName], target[propName], this._additiveValue, 1);
      }
    };

    return Track;
  }();

  var Animator = function () {
    function Animator(target, loop, additiveTo) {
      this._tracks = {};
      this._trackKeys = [];
      this._delay = 0;
      this._maxTime = 0;
      this._paused = false;
      this._started = 0;
      this._doneList = [];
      this._onframeList = [];
      this._clip = null;
      this._target = target;
      this._loop = loop;

      if (loop) {
        logError('Can\' use additive animation on looped animation.');
        return;
      }

      this._additiveAnimators = additiveTo;
    }

    Animator.prototype.getTarget = function () {
      return this._target;
    };

    Animator.prototype.changeTarget = function (target) {
      this._target = target;
    };

    Animator.prototype.when = function (time, props) {
      return this.whenWithKeys(time, props, keys(props));
    };

    Animator.prototype.whenWithKeys = function (time, props, propNames) {
      var tracks = this._tracks;

      for (var i = 0; i < propNames.length; i++) {
        var propName = propNames[i];
        var track = tracks[propName];

        if (!track) {
          track = tracks[propName] = new Track(propName);
          var initialValue = void 0;

          var additiveTrack = this._getAdditiveTrack(propName);

          if (additiveTrack) {
            var lastFinalKf = additiveTrack.keyframes[additiveTrack.keyframes.length - 1];
            initialValue = lastFinalKf && lastFinalKf.value;

            if (additiveTrack.isValueColor && initialValue) {
              initialValue = rgba2String(initialValue);
            }
          } else {
            initialValue = this._target[propName];
          }

          if (initialValue == null) {
            continue;
          }

          if (time !== 0) {
            track.addKeyframe(0, cloneValue(initialValue));
          }

          this._trackKeys.push(propName);
        }

        track.addKeyframe(time, cloneValue(props[propName]));
      }

      this._maxTime = Math.max(this._maxTime, time);
      return this;
    };

    Animator.prototype.during = function (callback) {
      this._onframeList.push(callback);

      return this;
    };

    Animator.prototype.pause = function () {
      this._clip.pause();

      this._paused = true;
    };

    Animator.prototype.resume = function () {
      this._clip.resume();

      this._paused = false;
    };

    Animator.prototype.isPaused = function () {
      return !!this._paused;
    };

    Animator.prototype._doneCallback = function () {
      this._tracks = null;
      this._clip = null;
      var doneList = this._doneList;
      var len = doneList.length;

      for (var i = 0; i < len; i++) {
        doneList[i].call(this);
      }
    };

    Animator.prototype._getAdditiveTrack = function (trackName) {
      var additiveTrack;
      var additiveAnimators = this._additiveAnimators;

      if (additiveAnimators) {
        for (var i = 0; i < additiveAnimators.length; i++) {
          var track = additiveAnimators[i].getTrack(trackName);

          if (track) {
            additiveTrack = track;
          }
        }
      }

      return additiveTrack;
    };

    Animator.prototype.start = function (easing, forceAnimate) {
      if (this._started > 0) {
        return;
      }

      this._started = 1;
      var self = this;
      var tracks = [];

      for (var i = 0; i < this._trackKeys.length; i++) {
        var propName = this._trackKeys[i];
        var track = this._tracks[propName];

        var additiveTrack = this._getAdditiveTrack(propName);

        var kfs = track.keyframes;
        track.prepare(additiveTrack);

        if (track.needsAnimate()) {
          tracks.push(track);
        } else if (!track.interpolable) {
          var lastKf = kfs[kfs.length - 1];

          if (lastKf) {
            self._target[track.propName] = lastKf.value;
          }
        }
      }

      if (tracks.length || forceAnimate) {
        var clip = new Clip({
          life: this._maxTime,
          loop: this._loop,
          delay: this._delay,
          onframe: function (percent) {
            self._started = 2;
            var additiveAnimators = self._additiveAnimators;

            if (additiveAnimators) {
              var stillHasAdditiveAnimator = false;

              for (var i = 0; i < additiveAnimators.length; i++) {
                if (additiveAnimators[i]._clip) {
                  stillHasAdditiveAnimator = true;
                  break;
                }
              }

              if (!stillHasAdditiveAnimator) {
                self._additiveAnimators = null;
              }
            }

            for (var i = 0; i < tracks.length; i++) {
              tracks[i].step(self._target, percent);
            }

            for (var i = 0; i < self._onframeList.length; i++) {
              self._onframeList[i](self._target, percent);
            }
          },
          ondestroy: function () {
            for (var i = 0; i < tracks.length; i++) {
              tracks[i].setFinished();
            }

            self._doneCallback();
          }
        });
        this._clip = clip;

        if (this.animation) {
          this.animation.addClip(clip);
        }

        if (easing && easing !== 'spline') {
          clip.easing = easing;
        }
      } else {
        this._doneCallback();
      }

      return this;
    };

    Animator.prototype.stop = function (forwardToLast) {
      if (!this._clip) {
        return;
      }

      var clip = this._clip;
      var animation = this.animation;

      if (forwardToLast) {
        clip.onframe(1);
      }

      if (animation) {
        animation.removeClip(clip);
      }

      this._clip = null;
    };

    Animator.prototype.delay = function (time) {
      this._delay = time;
      return this;
    };

    Animator.prototype.done = function (cb) {
      if (cb) {
        this._doneList.push(cb);
      }

      return this;
    };

    Animator.prototype.getClip = function () {
      return this._clip;
    };

    Animator.prototype.getTrack = function (propName) {
      return this._tracks[propName];
    };

    Animator.prototype.stopTracks = function (propNames, forwardToLast) {
      if (!propNames.length || !this._clip) {
        return true;
      }

      var tracks = this._tracks;
      var tracksKeys = this._trackKeys;

      for (var i = 0; i < propNames.length; i++) {
        var track = tracks[propNames[i]];

        if (track) {
          if (forwardToLast) {
            track.step(this._target, 1);
          } else if (this._started === 1) {
            track.step(this._target, 0);
          }

          track.setFinished();
        }
      }

      var allAborted = true;

      for (var i = 0; i < tracksKeys.length; i++) {
        if (!tracks[tracksKeys[i]].isFinished()) {
          allAborted = false;
          break;
        }
      }

      if (allAborted && this.animation) {
        this.animation.removeClip(this._clip);
        this._clip = null;
      }

      return allAborted;
    };

    Animator.prototype.saveFinalToTarget = function (target, trackKeys) {
      if (!target) {
        return;
      }

      trackKeys = trackKeys || this._trackKeys;

      for (var i = 0; i < trackKeys.length; i++) {
        var propName = trackKeys[i];
        var track = this._tracks[propName];

        if (!track || track.isFinished()) {
          continue;
        }

        var kfs = track.keyframes;
        var lastKf = kfs[kfs.length - 1];

        if (lastKf) {
          var val = cloneValue(lastKf.value);

          if (track.isValueColor) {
            val = rgba2String(val);
          }

          target[propName] = val;
        }
      }
    };

    Animator.prototype.__changeFinalValue = function (finalProps, trackKeys) {
      trackKeys = trackKeys || keys(finalProps);

      for (var i = 0; i < trackKeys.length; i++) {
        var propName = trackKeys[i];
        var track = this._tracks[propName];

        if (!track) {
          continue;
        }

        var kfs = track.keyframes;

        if (kfs.length > 1) {
          var lastKf = kfs.pop();
          track.addKeyframe(lastKf.time, finalProps[propName]);
          track.prepare(track.getAdditiveTrack());
        }
      }
    };

    return Animator;
  }();

  var Animation = function (_super) {
    __extends(Animation, _super);

    function Animation(opts) {
      var _this = _super.call(this) || this;

      _this._running = false;
      _this._time = 0;
      _this._pausedTime = 0;
      _this._pauseStart = 0;
      _this._paused = false;
      opts = opts || {};
      _this.stage = opts.stage || {};

      _this.onframe = opts.onframe || function () {};

      return _this;
    }

    Animation.prototype.addClip = function (clip) {
      if (clip.animation) {
        this.removeClip(clip);
      }

      if (!this._clipsHead) {
        this._clipsHead = this._clipsTail = clip;
      } else {
        this._clipsTail.next = clip;
        clip.prev = this._clipsTail;
        clip.next = null;
        this._clipsTail = clip;
      }

      clip.animation = this;
    };

    Animation.prototype.addAnimator = function (animator) {
      animator.animation = this;
      var clip = animator.getClip();

      if (clip) {
        this.addClip(clip);
      }
    };

    Animation.prototype.removeClip = function (clip) {
      if (!clip.animation) {
        return;
      }

      var prev = clip.prev;
      var next = clip.next;

      if (prev) {
        prev.next = next;
      } else {
        this._clipsHead = next;
      }

      if (next) {
        next.prev = prev;
      } else {
        this._clipsTail = prev;
      }

      clip.next = clip.prev = clip.animation = null;
    };

    Animation.prototype.removeAnimator = function (animator) {
      var clip = animator.getClip();

      if (clip) {
        this.removeClip(clip);
      }

      animator.animation = null;
    };

    Animation.prototype.update = function () {
      var time = new Date().getTime() - this._pausedTime;

      var delta = time - this._time;
      var clip = this._clipsHead;

      while (clip) {
        var nextClip = clip.next;
        var finished = clip.step(time, delta);

        if (finished) {
          clip.ondestroy && clip.ondestroy();
          this.removeClip(clip);
          clip = nextClip;
        } else {
          clip = nextClip;
        }
      }

      this._time = time;
      this.onframe(delta);
      this.trigger('frame', delta);

      if (this.stage.update) {
        this.stage.update();
      }
    };

    Animation.prototype._startLoop = function () {
      var self = this;
      this._running = true;

      function step() {
        if (self._running) {
          requestAnimationFrame$1(step);
          !self._paused && self.update();
        }
      }

      requestAnimationFrame$1(step);
    };

    Animation.prototype.start = function () {
      if (this._running) {
        return;
      }

      this._time = new Date().getTime();
      this._pausedTime = 0;

      this._startLoop();
    };

    Animation.prototype.stop = function () {
      this._running = false;
    };

    Animation.prototype.pause = function () {
      if (!this._paused) {
        this._pauseStart = new Date().getTime();
        this._paused = true;
      }
    };

    Animation.prototype.resume = function () {
      if (this._paused) {
        this._pausedTime += new Date().getTime() - this._pauseStart;
        this._paused = false;
      }
    };

    Animation.prototype.clear = function () {
      var clip = this._clipsHead;

      while (clip) {
        var nextClip = clip.next;
        clip.prev = clip.next = clip.animation = null;
        clip = nextClip;
      }

      this._clipsHead = this._clipsTail = null;
    };

    Animation.prototype.isFinished = function () {
      return this._clipsHead == null;
    };

    Animation.prototype.animate = function (target, options) {
      options = options || {};
      this.start();
      var animator = new Animator(target, options.loop);
      this.addAnimator(animator);
      return animator;
    };

    return Animation;
  }(Eventful);

  var TOUCH_CLICK_DELAY = 300;
  var globalEventSupported = env.domSupported;

  var localNativeListenerNames = function () {
    var mouseHandlerNames = ['click', 'dblclick', 'mousewheel', 'wheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu'];
    var touchHandlerNames = ['touchstart', 'touchend', 'touchmove'];
    var pointerEventNameMap = {
      pointerdown: 1,
      pointerup: 1,
      pointermove: 1,
      pointerout: 1
    };
    var pointerHandlerNames = map(mouseHandlerNames, function (name) {
      var nm = name.replace('mouse', 'pointer');
      return pointerEventNameMap.hasOwnProperty(nm) ? nm : name;
    });
    return {
      mouse: mouseHandlerNames,
      touch: touchHandlerNames,
      pointer: pointerHandlerNames
    };
  }();

  var globalNativeListenerNames = {
    mouse: ['mousemove', 'mouseup'],
    pointer: ['pointermove', 'pointerup']
  };
  var wheelEventSupported = false;

  function isPointerFromTouch(event) {
    var pointerType = event.pointerType;
    return pointerType === 'pen' || pointerType === 'touch';
  }

  function setTouchTimer(scope) {
    scope.touching = true;

    if (scope.touchTimer != null) {
      clearTimeout(scope.touchTimer);
      scope.touchTimer = null;
    }

    scope.touchTimer = setTimeout(function () {
      scope.touching = false;
      scope.touchTimer = null;
    }, 700);
  }

  function markTouch(event) {
    event && (event.zrByTouch = true);
  }

  function normalizeGlobalEvent(instance, event) {
    return normalizeEvent(instance.dom, new FakeGlobalEvent(instance, event), true);
  }

  function isLocalEl(instance, el) {
    var elTmp = el;
    var isLocal = false;

    while (elTmp && elTmp.nodeType !== 9 && !(isLocal = elTmp.domBelongToZr || elTmp !== el && elTmp === instance.painterRoot)) {
      elTmp = elTmp.parentNode;
    }

    return isLocal;
  }

  var FakeGlobalEvent = function () {
    function FakeGlobalEvent(instance, event) {
      this.stopPropagation = noop;
      this.stopImmediatePropagation = noop;
      this.preventDefault = noop;
      this.type = event.type;
      this.target = this.currentTarget = instance.dom;
      this.pointerType = event.pointerType;
      this.clientX = event.clientX;
      this.clientY = event.clientY;
    }

    return FakeGlobalEvent;
  }();

  var localDOMHandlers = {
    mousedown: function (event) {
      event = normalizeEvent(this.dom, event);
      this.__mayPointerCapture = [event.zrX, event.zrY];
      this.trigger('mousedown', event);
    },
    mousemove: function (event) {
      event = normalizeEvent(this.dom, event);
      var downPoint = this.__mayPointerCapture;

      if (downPoint && (event.zrX !== downPoint[0] || event.zrY !== downPoint[1])) {
        this.__togglePointerCapture(true);
      }

      this.trigger('mousemove', event);
    },
    mouseup: function (event) {
      event = normalizeEvent(this.dom, event);

      this.__togglePointerCapture(false);

      this.trigger('mouseup', event);
    },
    mouseout: function (event) {
      event = normalizeEvent(this.dom, event);

      if (this.__pointerCapturing) {
        event.zrEventControl = 'no_globalout';
      }

      var element = event.toElement || event.relatedTarget;
      event.zrIsToLocalDOM = isLocalEl(this, element);
      this.trigger('mouseout', event);
    },
    wheel: function (event) {
      wheelEventSupported = true;
      event = normalizeEvent(this.dom, event);
      this.trigger('mousewheel', event);
    },
    mousewheel: function (event) {
      if (wheelEventSupported) {
        return;
      }

      event = normalizeEvent(this.dom, event);
      this.trigger('mousewheel', event);
    },
    touchstart: function (event) {
      event = normalizeEvent(this.dom, event);
      markTouch(event);
      this.__lastTouchMoment = new Date();
      this.handler.processGesture(event, 'start');
      localDOMHandlers.mousemove.call(this, event);
      localDOMHandlers.mousedown.call(this, event);
    },
    touchmove: function (event) {
      event = normalizeEvent(this.dom, event);
      markTouch(event);
      this.handler.processGesture(event, 'change');
      localDOMHandlers.mousemove.call(this, event);
    },
    touchend: function (event) {
      event = normalizeEvent(this.dom, event);
      markTouch(event);
      this.handler.processGesture(event, 'end');
      localDOMHandlers.mouseup.call(this, event);

      if (+new Date() - +this.__lastTouchMoment < TOUCH_CLICK_DELAY) {
        localDOMHandlers.click.call(this, event);
      }
    },
    pointerdown: function (event) {
      localDOMHandlers.mousedown.call(this, event);
    },
    pointermove: function (event) {
      if (!isPointerFromTouch(event)) {
        localDOMHandlers.mousemove.call(this, event);
      }
    },
    pointerup: function (event) {
      localDOMHandlers.mouseup.call(this, event);
    },
    pointerout: function (event) {
      if (!isPointerFromTouch(event)) {
        localDOMHandlers.mouseout.call(this, event);
      }
    }
  };
  each(['click', 'dblclick', 'contextmenu'], function (name) {
    localDOMHandlers[name] = function (event) {
      event = normalizeEvent(this.dom, event);
      this.trigger(name, event);
    };
  });
  var globalDOMHandlers = {
    pointermove: function (event) {
      if (!isPointerFromTouch(event)) {
        globalDOMHandlers.mousemove.call(this, event);
      }
    },
    pointerup: function (event) {
      globalDOMHandlers.mouseup.call(this, event);
    },
    mousemove: function (event) {
      this.trigger('mousemove', event);
    },
    mouseup: function (event) {
      var pointerCaptureReleasing = this.__pointerCapturing;

      this.__togglePointerCapture(false);

      this.trigger('mouseup', event);

      if (pointerCaptureReleasing) {
        event.zrEventControl = 'only_globalout';
        this.trigger('mouseout', event);
      }
    }
  };

  function mountLocalDOMEventListeners(instance, scope) {
    var domHandlers = scope.domHandlers;

    if (env.pointerEventsSupported) {
      each(localNativeListenerNames.pointer, function (nativeEventName) {
        mountSingleDOMEventListener(scope, nativeEventName, function (event) {
          domHandlers[nativeEventName].call(instance, event);
        });
      });
    } else {
      if (env.touchEventsSupported) {
        each(localNativeListenerNames.touch, function (nativeEventName) {
          mountSingleDOMEventListener(scope, nativeEventName, function (event) {
            domHandlers[nativeEventName].call(instance, event);
            setTouchTimer(scope);
          });
        });
      }

      each(localNativeListenerNames.mouse, function (nativeEventName) {
        mountSingleDOMEventListener(scope, nativeEventName, function (event) {
          event = getNativeEvent(event);

          if (!scope.touching) {
            domHandlers[nativeEventName].call(instance, event);
          }
        });
      });
    }
  }

  function mountGlobalDOMEventListeners(instance, scope) {
    if (env.pointerEventsSupported) {
      each(globalNativeListenerNames.pointer, mount);
    } else if (!env.touchEventsSupported) {
      each(globalNativeListenerNames.mouse, mount);
    }

    function mount(nativeEventName) {
      function nativeEventListener(event) {
        event = getNativeEvent(event);

        if (!isLocalEl(instance, event.target)) {
          event = normalizeGlobalEvent(instance, event);
          scope.domHandlers[nativeEventName].call(instance, event);
        }
      }

      mountSingleDOMEventListener(scope, nativeEventName, nativeEventListener, {
        capture: true
      });
    }
  }

  function mountSingleDOMEventListener(scope, nativeEventName, listener, opt) {
    scope.mounted[nativeEventName] = listener;
    scope.listenerOpts[nativeEventName] = opt;
    addEventListener(scope.domTarget, nativeEventName, listener, opt);
  }

  function unmountDOMEventListeners(scope) {
    var mounted = scope.mounted;

    for (var nativeEventName in mounted) {
      if (mounted.hasOwnProperty(nativeEventName)) {
        removeEventListener(scope.domTarget, nativeEventName, mounted[nativeEventName], scope.listenerOpts[nativeEventName]);
      }
    }

    scope.mounted = {};
  }

  var DOMHandlerScope = function () {
    function DOMHandlerScope(domTarget, domHandlers) {
      this.mounted = {};
      this.listenerOpts = {};
      this.touching = false;
      this.domTarget = domTarget;
      this.domHandlers = domHandlers;
    }

    return DOMHandlerScope;
  }();

  var HandlerDomProxy = function (_super) {
    __extends(HandlerDomProxy, _super);

    function HandlerDomProxy(dom, painterRoot) {
      var _this = _super.call(this) || this;

      _this.__pointerCapturing = false;
      _this.dom = dom;
      _this.painterRoot = painterRoot;
      _this._localHandlerScope = new DOMHandlerScope(dom, localDOMHandlers);

      if (globalEventSupported) {
        _this._globalHandlerScope = new DOMHandlerScope(document, globalDOMHandlers);
      }

      mountLocalDOMEventListeners(_this, _this._localHandlerScope);
      return _this;
    }

    HandlerDomProxy.prototype.dispose = function () {
      unmountDOMEventListeners(this._localHandlerScope);

      if (globalEventSupported) {
        unmountDOMEventListeners(this._globalHandlerScope);
      }
    };

    HandlerDomProxy.prototype.setCursor = function (cursorStyle) {
      this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');
    };

    HandlerDomProxy.prototype.__togglePointerCapture = function (isPointerCapturing) {
      this.__mayPointerCapture = null;

      if (globalEventSupported && +this.__pointerCapturing ^ +isPointerCapturing) {
        this.__pointerCapturing = isPointerCapturing;
        var globalHandlerScope = this._globalHandlerScope;
        isPointerCapturing ? mountGlobalDOMEventListeners(this, globalHandlerScope) : unmountDOMEventListeners(globalHandlerScope);
      }
    };

    return HandlerDomProxy;
  }(Eventful);

  function create$1() {
    return [1, 0, 0, 1, 0, 0];
  }

  function identity(out) {
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    out[4] = 0;
    out[5] = 0;
    return out;
  }

  function copy$1(out, m) {
    out[0] = m[0];
    out[1] = m[1];
    out[2] = m[2];
    out[3] = m[3];
    out[4] = m[4];
    out[5] = m[5];
    return out;
  }

  function mul(out, m1, m2) {
    var out0 = m1[0] * m2[0] + m1[2] * m2[1];
    var out1 = m1[1] * m2[0] + m1[3] * m2[1];
    var out2 = m1[0] * m2[2] + m1[2] * m2[3];
    var out3 = m1[1] * m2[2] + m1[3] * m2[3];
    var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];
    var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];
    out[0] = out0;
    out[1] = out1;
    out[2] = out2;
    out[3] = out3;
    out[4] = out4;
    out[5] = out5;
    return out;
  }

  function translate(out, a, v) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    out[4] = a[4] + v[0];
    out[5] = a[5] + v[1];
    return out;
  }

  function rotate(out, a, rad) {
    var aa = a[0];
    var ac = a[2];
    var atx = a[4];
    var ab = a[1];
    var ad = a[3];
    var aty = a[5];
    var st = Math.sin(rad);
    var ct = Math.cos(rad);
    out[0] = aa * ct + ab * st;
    out[1] = -aa * st + ab * ct;
    out[2] = ac * ct + ad * st;
    out[3] = -ac * st + ct * ad;
    out[4] = ct * atx + st * aty;
    out[5] = ct * aty - st * atx;
    return out;
  }

  function scale$1(out, a, v) {
    var vx = v[0];
    var vy = v[1];
    out[0] = a[0] * vx;
    out[1] = a[1] * vy;
    out[2] = a[2] * vx;
    out[3] = a[3] * vy;
    out[4] = a[4] * vx;
    out[5] = a[5] * vy;
    return out;
  }

  function invert(out, a) {
    var aa = a[0];
    var ac = a[2];
    var atx = a[4];
    var ab = a[1];
    var ad = a[3];
    var aty = a[5];
    var det = aa * ad - ab * ac;

    if (!det) {
      return null;
    }

    det = 1.0 / det;
    out[0] = ad * det;
    out[1] = -ab * det;
    out[2] = -ac * det;
    out[3] = aa * det;
    out[4] = (ac * aty - ad * atx) * det;
    out[5] = (ab * atx - aa * aty) * det;
    return out;
  }

  var mIdentity = identity;
  var EPSILON = 5e-5;

  function isNotAroundZero(val) {
    return val > EPSILON || val < -EPSILON;
  }

  var scaleTmp = [];
  var tmpTransform = [];
  var originTransform = create$1();
  var abs = Math.abs;

  var Transformable = function () {
    function Transformable() {}

    Transformable.prototype.setPosition = function (arr) {
      this.x = arr[0];
      this.y = arr[1];
    };

    Transformable.prototype.setScale = function (arr) {
      this.scaleX = arr[0];
      this.scaleY = arr[1];
    };

    Transformable.prototype.setOrigin = function (arr) {
      this.originX = arr[0];
      this.originY = arr[1];
    };

    Transformable.prototype.needLocalTransform = function () {
      return isNotAroundZero(this.rotation) || isNotAroundZero(this.x) || isNotAroundZero(this.y) || isNotAroundZero(this.scaleX - 1) || isNotAroundZero(this.scaleY - 1);
    };

    Transformable.prototype.updateTransform = function () {
      var parent = this.parent;
      var parentHasTransform = parent && parent.transform;
      var needLocalTransform = this.needLocalTransform();
      var m = this.transform;

      if (!(needLocalTransform || parentHasTransform)) {
        m && mIdentity(m);
        return;
      }

      m = m || create$1();

      if (needLocalTransform) {
        this.getLocalTransform(m);
      } else {
        mIdentity(m);
      }

      if (parentHasTransform) {
        if (needLocalTransform) {
          mul(m, parent.transform, m);
        } else {
          copy$1(m, parent.transform);
        }
      }

      this.transform = m;

      this._resolveGlobalScaleRatio(m);
    };

    Transformable.prototype._resolveGlobalScaleRatio = function (m) {
      var globalScaleRatio = this.globalScaleRatio;

      if (globalScaleRatio != null && globalScaleRatio !== 1) {
        this.getGlobalScale(scaleTmp);
        var relX = scaleTmp[0] < 0 ? -1 : 1;
        var relY = scaleTmp[1] < 0 ? -1 : 1;
        var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;
        var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;
        m[0] *= sx;
        m[1] *= sx;
        m[2] *= sy;
        m[3] *= sy;
      }

      this.invTransform = this.invTransform || create$1();
      invert(this.invTransform, m);
    };

    Transformable.prototype.getLocalTransform = function (m) {
      return Transformable.getLocalTransform(this, m);
    };

    Transformable.prototype.getComputedTransform = function () {
      var transformNode = this;
      var ancestors = [];

      while (transformNode) {
        ancestors.push(transformNode);
        transformNode = transformNode.parent;
      }

      while (transformNode = ancestors.pop()) {
        transformNode.updateTransform();
      }

      return this.transform;
    };

    Transformable.prototype.setLocalTransform = function (m) {
      if (!m) {
        return;
      }

      var sx = m[0] * m[0] + m[1] * m[1];
      var sy = m[2] * m[2] + m[3] * m[3];

      if (isNotAroundZero(sx - 1)) {
        sx = Math.sqrt(sx);
      }

      if (isNotAroundZero(sy - 1)) {
        sy = Math.sqrt(sy);
      }

      this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);

      if (m[0] < 0) {
        sx = -sx;
      }

      if (m[3] < 0) {
        sy = -sy;
      }

      if (sx < 0 && sy < 0) {
        this.rotation += Math.PI;
        sx = -sx;
        sy = -sy;
      }

      this.x = m[4];
      this.y = m[5];
      this.scaleX = sx;
      this.scaleY = sy;
    };

    Transformable.prototype.decomposeTransform = function () {
      if (!this.transform) {
        return;
      }

      var parent = this.parent;
      var m = this.transform;

      if (parent && parent.transform) {
        mul(tmpTransform, parent.invTransform, m);
        m = tmpTransform;
      }

      var ox = this.originX;
      var oy = this.originY;

      if (ox || oy) {
        originTransform[4] = ox;
        originTransform[5] = oy;
        mul(tmpTransform, m, originTransform);
        tmpTransform[4] -= ox;
        tmpTransform[5] -= oy;
        m = tmpTransform;
      }

      this.setLocalTransform(m);
    };

    Transformable.prototype.getGlobalScale = function (out) {
      var m = this.transform;
      out = out || [];

      if (!m) {
        out[0] = 1;
        out[1] = 1;
        return out;
      }

      out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);
      out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);

      if (m[0] < 0) {
        out[0] = -out[0];
      }

      if (m[3] < 0) {
        out[1] = -out[1];
      }

      return out;
    };

    Transformable.prototype.transformCoordToLocal = function (x, y) {
      var v2 = [x, y];
      var invTransform = this.invTransform;

      if (invTransform) {
        applyTransform(v2, v2, invTransform);
      }

      return v2;
    };

    Transformable.prototype.transformCoordToGlobal = function (x, y) {
      var v2 = [x, y];
      var transform = this.transform;

      if (transform) {
        applyTransform(v2, v2, transform);
      }

      return v2;
    };

    Transformable.prototype.getLineScale = function () {
      var m = this.transform;
      return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10 ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1])) : 1;
    };

    Transformable.getLocalTransform = function (target, m) {
      m = m || [];
      mIdentity(m);
      var ox = target.originX || 0;
      var oy = target.originY || 0;
      var sx = target.scaleX;
      var sy = target.scaleY;
      var rotation = target.rotation || 0;
      var x = target.x;
      var y = target.y;
      m[4] -= ox;
      m[5] -= oy;
      m[0] *= sx;
      m[1] *= sy;
      m[2] *= sx;
      m[3] *= sy;
      m[4] *= sx;
      m[5] *= sy;

      if (rotation) {
        rotate(m, m, rotation);
      }

      m[4] += ox;
      m[5] += oy;
      m[4] += x;
      m[5] += y;
      return m;
    };

    Transformable.initDefaultProps = function () {
      var proto = Transformable.prototype;
      proto.x = 0;
      proto.y = 0;
      proto.scaleX = 1;
      proto.scaleY = 1;
      proto.originX = 0;
      proto.originY = 0;
      proto.rotation = 0;
      proto.globalScaleRatio = 1;
    }();

    return Transformable;
  }();

  var Point = function () {
    function Point(x, y) {
      this.x = x || 0;
      this.y = y || 0;
    }

    Point.prototype.copy = function (other) {
      this.x = other.x;
      this.y = other.y;
      return this;
    };

    Point.prototype.clone = function () {
      return new Point(this.x, this.y);
    };

    Point.prototype.set = function (x, y) {
      this.x = x;
      this.y = y;
      return this;
    };

    Point.prototype.equal = function (other) {
      return other.x === this.x && other.y === this.y;
    };

    Point.prototype.add = function (other) {
      this.x += other.x;
      this.y += other.y;
      return this;
    };

    Point.prototype.scale = function (scalar) {
      this.x *= scalar;
      this.y *= scalar;
    };

    Point.prototype.scaleAndAdd = function (other, scalar) {
      this.x += other.x * scalar;
      this.y += other.y * scalar;
    };

    Point.prototype.sub = function (other) {
      this.x -= other.x;
      this.y -= other.y;
      return this;
    };

    Point.prototype.dot = function (other) {
      return this.x * other.x + this.y * other.y;
    };

    Point.prototype.len = function () {
      return Math.sqrt(this.x * this.x + this.y * this.y);
    };

    Point.prototype.lenSquare = function () {
      return this.x * this.x + this.y * this.y;
    };

    Point.prototype.normalize = function () {
      var len = this.len();
      this.x /= len;
      this.y /= len;
      return this;
    };

    Point.prototype.distance = function (other) {
      var dx = this.x - other.x;
      var dy = this.y - other.y;
      return Math.sqrt(dx * dx + dy * dy);
    };

    Point.prototype.distanceSquare = function (other) {
      var dx = this.x - other.x;
      var dy = this.y - other.y;
      return dx * dx + dy * dy;
    };

    Point.prototype.negate = function () {
      this.x = -this.x;
      this.y = -this.y;
      return this;
    };

    Point.prototype.transform = function (m) {
      if (!m) {
        return;
      }

      var x = this.x;
      var y = this.y;
      this.x = m[0] * x + m[2] * y + m[4];
      this.y = m[1] * x + m[3] * y + m[5];
      return this;
    };

    Point.prototype.toArray = function (out) {
      out[0] = this.x;
      out[1] = this.y;
      return out;
    };

    Point.prototype.fromArray = function (input) {
      this.x = input[0];
      this.y = input[1];
    };

    Point.set = function (p, x, y) {
      p.x = x;
      p.y = y;
    };

    Point.copy = function (p, p2) {
      p.x = p2.x;
      p.y = p2.y;
    };

    Point.len = function (p) {
      return Math.sqrt(p.x * p.x + p.y * p.y);
    };

    Point.lenSquare = function (p) {
      return p.x * p.x + p.y * p.y;
    };

    Point.dot = function (p0, p1) {
      return p0.x * p1.x + p0.y * p1.y;
    };

    Point.add = function (out, p0, p1) {
      out.x = p0.x + p1.x;
      out.y = p0.y + p1.y;
    };

    Point.sub = function (out, p0, p1) {
      out.x = p0.x - p1.x;
      out.y = p0.y - p1.y;
    };

    Point.scale = function (out, p0, scalar) {
      out.x = p0.x * scalar;
      out.y = p0.y * scalar;
    };

    Point.scaleAndAdd = function (out, p0, p1, scalar) {
      out.x = p0.x + p1.x * scalar;
      out.y = p0.y + p1.y * scalar;
    };

    Point.lerp = function (out, p0, p1, t) {
      var onet = 1 - t;
      out.x = onet * p0.x + t * p1.x;
      out.y = onet * p0.y + t * p1.y;
    };

    return Point;
  }();

  var mathMin = Math.min;
  var mathMax = Math.max;
  var lt = new Point();
  var rb = new Point();
  var lb = new Point();
  var rt = new Point();
  var minTv = new Point();
  var maxTv = new Point();

  var BoundingRect = function () {
    function BoundingRect(x, y, width, height) {
      if (width < 0) {
        x = x + width;
        width = -width;
      }

      if (height < 0) {
        y = y + height;
        height = -height;
      }

      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
    }

    BoundingRect.prototype.union = function (other) {
      var x = mathMin(other.x, this.x);
      var y = mathMin(other.y, this.y);
      this.width = mathMax(other.x + other.width, this.x + this.width) - x;
      this.height = mathMax(other.y + other.height, this.y + this.height) - y;
      this.x = x;
      this.y = y;
    };

    BoundingRect.prototype.applyTransform = function (m) {
      BoundingRect.applyTransform(this, this, m);
    };

    BoundingRect.prototype.calculateTransform = function (b) {
      var a = this;
      var sx = b.width / a.width;
      var sy = b.height / a.height;
      var m = create$1();
      translate(m, m, [-a.x, -a.y]);
      scale$1(m, m, [sx, sy]);
      translate(m, m, [b.x, b.y]);
      return m;
    };

    BoundingRect.prototype.intersect = function (b, mtv) {
      if (!b) {
        return false;
      }

      if (!(b instanceof BoundingRect)) {
        b = BoundingRect.create(b);
      }

      var a = this;
      var ax0 = a.x;
      var ax1 = a.x + a.width;
      var ay0 = a.y;
      var ay1 = a.y + a.height;
      var bx0 = b.x;
      var bx1 = b.x + b.width;
      var by0 = b.y;
      var by1 = b.y + b.height;
      var overlap = !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);

      if (mtv) {
        var dMin = Infinity;
        var dMax = 0;
        var d0 = Math.abs(ax1 - bx0);
        var d1 = Math.abs(bx1 - ax0);
        var d2 = Math.abs(ay1 - by0);
        var d3 = Math.abs(by1 - ay0);
        var dx = Math.min(d0, d1);
        var dy = Math.min(d2, d3);

        if (ax1 < bx0 || bx1 < ax0) {
          if (dx > dMax) {
            dMax = dx;

            if (d0 < d1) {
              Point.set(maxTv, -d0, 0);
            } else {
              Point.set(maxTv, d1, 0);
            }
          }
        } else {
          if (dx < dMin) {
            dMin = dx;

            if (d0 < d1) {
              Point.set(minTv, d0, 0);
            } else {
              Point.set(minTv, -d1, 0);
            }
          }
        }

        if (ay1 < by0 || by1 < ay0) {
          if (dy > dMax) {
            dMax = dy;

            if (d2 < d3) {
              Point.set(maxTv, 0, -d2);
            } else {
              Point.set(maxTv, 0, d3);
            }
          }
        } else {
          if (dx < dMin) {
            dMin = dx;

            if (d2 < d3) {
              Point.set(minTv, 0, d2);
            } else {
              Point.set(minTv, 0, -d3);
            }
          }
        }
      }

      if (mtv) {
        Point.copy(mtv, overlap ? minTv : maxTv);
      }

      return overlap;
    };

    BoundingRect.prototype.contain = function (x, y) {
      var rect = this;
      return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
    };

    BoundingRect.prototype.clone = function () {
      return new BoundingRect(this.x, this.y, this.width, this.height);
    };

    BoundingRect.prototype.copy = function (other) {
      BoundingRect.copy(this, other);
    };

    BoundingRect.prototype.plain = function () {
      return {
        x: this.x,
        y: this.y,
        width: this.width,
        height: this.height
      };
    };

    BoundingRect.create = function (rect) {
      return new BoundingRect(rect.x, rect.y, rect.width, rect.height);
    };

    BoundingRect.copy = function (target, source) {
      target.x = source.x;
      target.y = source.y;
      target.width = source.width;
      target.height = source.height;
    };

    BoundingRect.applyTransform = function (target, source, m) {
      if (!m) {
        if (target !== source) {
          BoundingRect.copy(target, source);
        }

        return;
      }

      if (m[1] < 1e-5 && m[1] > -1e-5 && m[2] < 1e-5 && m[2] > -1e-5) {
        var sx = m[0];
        var sy = m[3];
        var tx = m[4];
        var ty = m[5];
        target.x = source.x * sx + tx;
        target.y = source.y * sy + ty;
        target.width = source.width * sx;
        target.height = source.height * sy;

        if (target.width < 0) {
          target.x += target.width;
          target.width = -target.width;
        }

        if (target.height < 0) {
          target.y += target.height;
          target.height = -target.height;
        }

        return;
      }

      lt.x = lb.x = source.x;
      lt.y = rt.y = source.y;
      rb.x = rt.x = source.x + source.width;
      rb.y = lb.y = source.y + source.height;
      lt.transform(m);
      rt.transform(m);
      rb.transform(m);
      lb.transform(m);
      target.x = mathMin(lt.x, rb.x, lb.x, rt.x);
      target.y = mathMin(lt.y, rb.y, lb.y, rt.y);
      var maxX = mathMax(lt.x, rb.x, lb.x, rt.x);
      var maxY = mathMax(lt.y, rb.y, lb.y, rt.y);
      target.width = maxX - target.x;
      target.height = maxY - target.y;
    };

    return BoundingRect;
  }();

  var textWidthCache = {};
  var DEFAULT_FONT = '12px sans-serif';

  var _ctx;

  var _cachedFont;

  function defaultMeasureText(text, font) {
    if (!_ctx) {
      _ctx = createCanvas().getContext('2d');
    }

    if (_cachedFont !== font) {
      _cachedFont = _ctx.font = font || DEFAULT_FONT;
    }

    return _ctx.measureText(text);
  }

  var methods$1 = {
    measureText: defaultMeasureText
  };

  function getWidth(text, font) {
    font = font || DEFAULT_FONT;
    var cacheOfFont = textWidthCache[font];

    if (!cacheOfFont) {
      cacheOfFont = textWidthCache[font] = new LRU(500);
    }

    var width = cacheOfFont.get(text);

    if (width == null) {
      width = methods$1.measureText(text, font).width;
      cacheOfFont.put(text, width);
    }

    return width;
  }

  function innerGetBoundingRect(text, font, textAlign, textBaseline) {
    var width = getWidth(text, font);
    var height = getLineHeight(font);
    var x = adjustTextX(0, width, textAlign);
    var y = adjustTextY(0, height, textBaseline);
    var rect = new BoundingRect(x, y, width, height);
    return rect;
  }

  function getBoundingRect(text, font, textAlign, textBaseline) {
    var textLines = ((text || '') + '').split('\n');
    var len = textLines.length;

    if (len === 1) {
      return innerGetBoundingRect(textLines[0], font, textAlign, textBaseline);
    } else {
      var uniondRect = new BoundingRect(0, 0, 0, 0);

      for (var i = 0; i < textLines.length; i++) {
        var rect = innerGetBoundingRect(textLines[i], font, textAlign, textBaseline);
        i === 0 ? uniondRect.copy(rect) : uniondRect.union(rect);
      }

      return uniondRect;
    }
  }

  function adjustTextX(x, width, textAlign) {
    if (textAlign === 'right') {
      x -= width;
    } else if (textAlign === 'center') {
      x -= width / 2;
    }

    return x;
  }

  function adjustTextY(y, height, verticalAlign) {
    if (verticalAlign === 'middle') {
      y -= height / 2;
    } else if (verticalAlign === 'bottom') {
      y -= height;
    }

    return y;
  }

  function getLineHeight(font) {
    return getWidth('国', font);
  }

  function parsePercent(value, maxValue) {
    if (typeof value === 'string') {
      if (value.lastIndexOf('%') >= 0) {
        return parseFloat(value) / 100 * maxValue;
      }

      return parseFloat(value);
    }

    return value;
  }

  function calculateTextPosition(out, opts, rect) {
    var textPosition = opts.position || 'inside';
    var distance = opts.distance != null ? opts.distance : 5;
    var height = rect.height;
    var width = rect.width;
    var halfHeight = height / 2;
    var x = rect.x;
    var y = rect.y;
    var textAlign = 'left';
    var textVerticalAlign = 'top';

    if (textPosition instanceof Array) {
      x += parsePercent(textPosition[0], rect.width);
      y += parsePercent(textPosition[1], rect.height);
      textAlign = null;
      textVerticalAlign = null;
    } else {
      switch (textPosition) {
        case 'left':
          x -= distance;
          y += halfHeight;
          textAlign = 'right';
          textVerticalAlign = 'middle';
          break;

        case 'right':
          x += distance + width;
          y += halfHeight;
          textVerticalAlign = 'middle';
          break;

        case 'top':
          x += width / 2;
          y -= distance;
          textAlign = 'center';
          textVerticalAlign = 'bottom';
          break;

        case 'bottom':
          x += width / 2;
          y += height + distance;
          textAlign = 'center';
          break;

        case 'inside':
          x += width / 2;
          y += halfHeight;
          textAlign = 'center';
          textVerticalAlign = 'middle';
          break;

        case 'insideLeft':
          x += distance;
          y += halfHeight;
          textVerticalAlign = 'middle';
          break;

        case 'insideRight':
          x += width - distance;
          y += halfHeight;
          textAlign = 'right';
          textVerticalAlign = 'middle';
          break;

        case 'insideTop':
          x += width / 2;
          y += distance;
          textAlign = 'center';
          break;

        case 'insideBottom':
          x += width / 2;
          y += height - distance;
          textAlign = 'center';
          textVerticalAlign = 'bottom';
          break;

        case 'insideTopLeft':
          x += distance;
          y += distance;
          break;

        case 'insideTopRight':
          x += width - distance;
          y += distance;
          textAlign = 'right';
          break;

        case 'insideBottomLeft':
          x += distance;
          y += height - distance;
          textVerticalAlign = 'bottom';
          break;

        case 'insideBottomRight':
          x += width - distance;
          y += height - distance;
          textAlign = 'right';
          textVerticalAlign = 'bottom';
          break;
      }
    }

    out = out || {};
    out.x = x;
    out.y = y;
    out.align = textAlign;
    out.verticalAlign = textVerticalAlign;
    return out;
  }

  var dpr = 1;

  if (typeof window !== 'undefined') {
    dpr = Math.max(window.devicePixelRatio || window.screen.deviceXDPI / window.screen.logicalXDPI || 1, 1);
  }

  var devicePixelRatio = dpr;
  var DARK_MODE_THRESHOLD = 0.4;
  var DARK_LABEL_COLOR = '#333';
  var LIGHT_LABEL_COLOR = '#ccc';
  var LIGHTER_LABEL_COLOR = '#eee';
  var PRESERVED_NORMAL_STATE = '__zr_normal__';
  var PRIMARY_STATES_KEYS = ['x', 'y', 'scaleX', 'scaleY', 'originX', 'originY', 'rotation', 'ignore'];
  var DEFAULT_ANIMATABLE_MAP = {
    x: true,
    y: true,
    scaleX: true,
    scaleY: true,
    originX: true,
    originY: true,
    rotation: true,
    ignore: false
  };
  var tmpTextPosCalcRes = {};
  var tmpBoundingRect = new BoundingRect(0, 0, 0, 0);

  var Element = function () {
    function Element(props) {
      this.id = guid();
      this.animators = [];
      this.currentStates = [];
      this.states = {};

      this._init(props);
    }

    Element.prototype._init = function (props) {
      this.attr(props);
    };

    Element.prototype.drift = function (dx, dy, e) {
      switch (this.draggable) {
        case 'horizontal':
          dy = 0;
          break;

        case 'vertical':
          dx = 0;
          break;
      }

      var m = this.transform;

      if (!m) {
        m = this.transform = [1, 0, 0, 1, 0, 0];
      }

      m[4] += dx;
      m[5] += dy;
      this.decomposeTransform();
      this.markRedraw();
    };

    Element.prototype.beforeUpdate = function () {};

    Element.prototype.afterUpdate = function () {};

    Element.prototype.update = function () {
      this.updateTransform();
      this.updateInnerText();
    };

    Element.prototype.updateInnerText = function (forceUpdate) {
      var textEl = this._textContent;

      if (textEl && (!textEl.ignore || forceUpdate)) {
        if (!this.textConfig) {
          this.textConfig = {};
        }

        var textConfig = this.textConfig;
        var isLocal = textConfig.local;
        var attachedTransform = textEl.attachedTransform;
        var textAlign = void 0;
        var textVerticalAlign = void 0;
        var textStyleChanged = false;

        if (isLocal) {
          attachedTransform.parent = this;
        } else {
          attachedTransform.parent = null;
        }

        var innerOrigin = false;
        attachedTransform.x = textEl.x;
        attachedTransform.y = textEl.y;
        attachedTransform.originX = textEl.originX;
        attachedTransform.originY = textEl.originY;
        attachedTransform.rotation = textEl.rotation;
        attachedTransform.scaleX = textEl.scaleX;
        attachedTransform.scaleY = textEl.scaleY;

        if (textConfig.position != null) {
          var layoutRect = tmpBoundingRect;

          if (textConfig.layoutRect) {
            layoutRect.copy(textConfig.layoutRect);
          } else {
            layoutRect.copy(this.getBoundingRect());
          }

          if (!isLocal) {
            layoutRect.applyTransform(this.transform);
          }

          if (this.calculateTextPosition) {
            this.calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
          } else {
            calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
          }

          attachedTransform.x = tmpTextPosCalcRes.x;
          attachedTransform.y = tmpTextPosCalcRes.y;
          textAlign = tmpTextPosCalcRes.align;
          textVerticalAlign = tmpTextPosCalcRes.verticalAlign;
          var textOrigin = textConfig.origin;

          if (textOrigin && textConfig.rotation != null) {
            var relOriginX = void 0;
            var relOriginY = void 0;

            if (textOrigin === 'center') {
              relOriginX = layoutRect.width * 0.5;
              relOriginY = layoutRect.height * 0.5;
            } else {
              relOriginX = parsePercent(textOrigin[0], layoutRect.width);
              relOriginY = parsePercent(textOrigin[1], layoutRect.height);
            }

            innerOrigin = true;
            attachedTransform.originX = -attachedTransform.x + relOriginX + (isLocal ? 0 : layoutRect.x);
            attachedTransform.originY = -attachedTransform.y + relOriginY + (isLocal ? 0 : layoutRect.y);
          }
        }

        if (textConfig.rotation != null) {
          attachedTransform.rotation = textConfig.rotation;
        }

        var textOffset = textConfig.offset;

        if (textOffset) {
          attachedTransform.x += textOffset[0];
          attachedTransform.y += textOffset[1];

          if (!innerOrigin) {
            attachedTransform.originX = -textOffset[0];
            attachedTransform.originY = -textOffset[1];
          }
        }

        var isInside = textConfig.inside == null ? typeof textConfig.position === 'string' && textConfig.position.indexOf('inside') >= 0 : textConfig.inside;
        var innerTextDefaultStyle = this._innerTextDefaultStyle || (this._innerTextDefaultStyle = {});
        var textFill = void 0;
        var textStroke = void 0;
        var autoStroke = void 0;

        if (isInside && this.canBeInsideText()) {
          textFill = textConfig.insideFill;
          textStroke = textConfig.insideStroke;

          if (textFill == null || textFill === 'auto') {
            textFill = this.getInsideTextFill();
          }

          if (textStroke == null || textStroke === 'auto') {
            textStroke = this.getInsideTextStroke(textFill);
            autoStroke = true;
          }
        } else {
          textFill = textConfig.outsideFill;
          textStroke = textConfig.outsideStroke;

          if (textFill == null || textFill === 'auto') {
            textFill = this.getOutsideFill();
          }

          if (textStroke == null || textStroke === 'auto') {
            textStroke = this.getOutsideStroke(textFill);
            autoStroke = true;
          }
        }

        textFill = textFill || '#000';

        if (textFill !== innerTextDefaultStyle.fill || textStroke !== innerTextDefaultStyle.stroke || autoStroke !== innerTextDefaultStyle.autoStroke || textAlign !== innerTextDefaultStyle.align || textVerticalAlign !== innerTextDefaultStyle.verticalAlign) {
          textStyleChanged = true;
          innerTextDefaultStyle.fill = textFill;
          innerTextDefaultStyle.stroke = textStroke;
          innerTextDefaultStyle.autoStroke = autoStroke;
          innerTextDefaultStyle.align = textAlign;
          innerTextDefaultStyle.verticalAlign = textVerticalAlign;
          textEl.setDefaultTextStyle(innerTextDefaultStyle);
        }

        if (textStyleChanged) {
          textEl.dirtyStyle();
        }

        textEl.markRedraw();
      }
    };

    Element.prototype.canBeInsideText = function () {
      return true;
    };

    Element.prototype.getInsideTextFill = function () {
      return '#fff';
    };

    Element.prototype.getInsideTextStroke = function (textFill) {
      return '#000';
    };

    Element.prototype.getOutsideFill = function () {
      return this.__zr && this.__zr.isDarkMode() ? LIGHT_LABEL_COLOR : DARK_LABEL_COLOR;
    };

    Element.prototype.getOutsideStroke = function (textFill) {
      var backgroundColor = this.__zr && this.__zr.getBackgroundColor();

      var colorArr = typeof backgroundColor === 'string' && parse(backgroundColor);

      if (!colorArr) {
        colorArr = [255, 255, 255, 1];
      }

      var alpha = colorArr[3];

      for (var i = 0; i < 3; i++) {
        colorArr[i] = colorArr[i] * alpha + 255 * (1 - alpha);
      }

      colorArr[3] = 1;
      return stringify(colorArr, 'rgba');
    };

    Element.prototype.traverse = function (cb, context) {};

    Element.prototype.attrKV = function (key, value) {
      if (key === 'textConfig') {
        this.setTextConfig(value);
      } else if (key === 'textContent') {
        this.setTextContent(value);
      } else if (key === 'clipPath') {
        this.setClipPath(value);
      } else if (key === 'extra') {
        this.extra = this.extra || {};
        extend(this.extra, value);
      } else {
        this[key] = value;
      }
    };

    Element.prototype.hide = function () {
      this.ignore = true;
      this.markRedraw();
    };

    Element.prototype.show = function () {
      this.ignore = false;
      this.markRedraw();
    };

    Element.prototype.attr = function (keyOrObj, value) {
      if (typeof keyOrObj === 'string') {
        this.attrKV(keyOrObj, value);
      } else if (isObject(keyOrObj)) {
        var obj = keyOrObj;
        var keysArr = keys(obj);

        for (var i = 0; i < keysArr.length; i++) {
          var key = keysArr[i];
          this.attrKV(key, keyOrObj[key]);
        }
      }

      this.markRedraw();
      return this;
    };

    Element.prototype.saveCurrentToNormalState = function (toState) {
      this._innerSaveToNormal(toState);

      var normalState = this._normalState;

      for (var i = 0; i < this.animators.length; i++) {
        var animator = this.animators[i];
        var fromStateTransition = animator.__fromStateTransition;

        if (fromStateTransition && fromStateTransition !== PRESERVED_NORMAL_STATE) {
          continue;
        }

        var targetName = animator.targetName;
        var target = targetName ? normalState[targetName] : normalState;
        animator.saveFinalToTarget(target);
      }
    };

    Element.prototype._innerSaveToNormal = function (toState) {
      var normalState = this._normalState;

      if (!normalState) {
        normalState = this._normalState = {};
      }

      if (toState.textConfig && !normalState.textConfig) {
        normalState.textConfig = this.textConfig;
      }

      this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS);
    };

    Element.prototype._savePrimaryToNormal = function (toState, normalState, primaryKeys) {
      for (var i = 0; i < primaryKeys.length; i++) {
        var key = primaryKeys[i];

        if (toState[key] != null && !(key in normalState)) {
          normalState[key] = this[key];
        }
      }
    };

    Element.prototype.hasState = function () {
      return this.currentStates.length > 0;
    };

    Element.prototype.getState = function (name) {
      return this.states[name];
    };

    Element.prototype.ensureState = function (name) {
      var states = this.states;

      if (!states[name]) {
        states[name] = {};
      }

      return states[name];
    };

    Element.prototype.clearStates = function () {
      this.useState(PRESERVED_NORMAL_STATE, false);
    };

    Element.prototype.useState = function (stateName, keepCurrentStates) {
      var toNormalState = stateName === PRESERVED_NORMAL_STATE;
      var hasStates = this.hasState();

      if (!hasStates && toNormalState) {
        return;
      }

      var currentStates = this.currentStates;
      var animationCfg = this.stateTransition;

      if (indexOf(currentStates, stateName) >= 0 && (keepCurrentStates || currentStates.length === 1)) {
        return;
      }

      var state;

      if (this.stateProxy && !toNormalState) {
        state = this.stateProxy(stateName);
      }

      if (!state) {
        state = this.states && this.states[stateName];
      }

      if (!state && !toNormalState) {
        logError("State " + stateName + " not exists.");
        return;
      }

      if (!toNormalState) {
        this.saveCurrentToNormalState(state);
      }

      var useHoverLayer = !!(state && state.hoverLayer);

      if (useHoverLayer) {
        this._toggleHoverLayerFlag(true);
      }

      this._applyStateObj(stateName, state, this._normalState, keepCurrentStates, !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg);

      if (this._textContent) {
        this._textContent.useState(stateName, keepCurrentStates);
      }

      if (this._textGuide) {
        this._textGuide.useState(stateName, keepCurrentStates);
      }

      if (toNormalState) {
        this.currentStates = [];
        this._normalState = {};
      } else {
        if (!keepCurrentStates) {
          this.currentStates = [stateName];
        } else {
          this.currentStates.push(stateName);
        }
      }

      this._updateAnimationTargets();

      this.markRedraw();

      if (!useHoverLayer && this.__inHover) {
        this._toggleHoverLayerFlag(false);

        this.__dirty &= ~Element.REDARAW_BIT;
      }

      return state;
    };

    Element.prototype.useStates = function (states) {
      if (!states.length) {
        this.clearStates();
      } else {
        var stateObjects = [];
        var currentStates = this.currentStates;
        var len = states.length;
        var notChange = len === currentStates.length;

        if (notChange) {
          for (var i = 0; i < len; i++) {
            if (states[i] !== currentStates[i]) {
              notChange = false;
              break;
            }
          }
        }

        if (notChange) {
          return;
        }

        for (var i = 0; i < len; i++) {
          var stateName = states[i];
          var stateObj = void 0;

          if (this.stateProxy) {
            stateObj = this.stateProxy(stateName, states);
          }

          if (!stateObj) {
            stateObj = this.states[stateName];
          }

          if (stateObj) {
            stateObjects.push(stateObj);
          }
        }

        var useHoverLayer = !!(stateObjects[len - 1] && stateObjects[len - 1].hoverLayer);

        if (useHoverLayer) {
          this._toggleHoverLayerFlag(true);
        }

        var mergedState = this._mergeStates(stateObjects);

        var animationCfg = this.stateTransition;
        this.saveCurrentToNormalState(mergedState);

        this._applyStateObj(states.join(','), mergedState, this._normalState, false, !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg);

        if (this._textContent) {
          this._textContent.useStates(states);
        }

        if (this._textGuide) {
          this._textGuide.useStates(states);
        }

        this._updateAnimationTargets();

        this.currentStates = states.slice();
        this.markRedraw();

        if (!useHoverLayer) {
          this._toggleHoverLayerFlag(false);

          this.__dirty &= ~Element.REDARAW_BIT;
        }
      }
    };

    Element.prototype._updateAnimationTargets = function () {
      for (var i = 0; i < this.animators.length; i++) {
        var animator = this.animators[i];

        if (animator.targetName) {
          animator.changeTarget(this[animator.targetName]);
        }
      }
    };

    Element.prototype.removeState = function (state) {
      var idx = indexOf(this.currentStates, state);

      if (idx >= 0) {
        var currentStates = this.currentStates.slice();
        currentStates.splice(idx, 1);
        this.useStates(currentStates);
      }
    };

    Element.prototype.replaceState = function (oldState, newState, forceAdd) {
      var currentStates = this.currentStates.slice();
      var idx = indexOf(currentStates, oldState);
      var newStateExists = indexOf(currentStates, newState) >= 0;

      if (idx >= 0) {
        if (!newStateExists) {
          currentStates[idx] = newState;
        } else {
          currentStates.splice(idx, 1);
        }
      } else if (forceAdd && !newStateExists) {
        currentStates.push(newState);
      }

      this.useStates(currentStates);
    };

    Element.prototype.toggleState = function (state, enable) {
      if (enable) {
        this.useState(state, true);
      } else {
        this.removeState(state);
      }
    };

    Element.prototype._mergeStates = function (states) {
      var mergedState = {};
      var mergedTextConfig;

      for (var i = 0; i < states.length; i++) {
        var state = states[i];
        extend(mergedState, state);

        if (state.textConfig) {
          mergedTextConfig = mergedTextConfig || {};
          extend(mergedTextConfig, state.textConfig);
        }
      }

      if (mergedTextConfig) {
        mergedState.textConfig = mergedTextConfig;
      }

      return mergedState;
    };

    Element.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
      var needsRestoreToNormal = !(state && keepCurrentStates);

      if (state && state.textConfig) {
        this.textConfig = extend({}, keepCurrentStates ? this.textConfig : normalState.textConfig);
        extend(this.textConfig, state.textConfig);
      } else if (needsRestoreToNormal) {
        if (normalState.textConfig) {
          this.textConfig = normalState.textConfig;
        }
      }

      var transitionTarget = {};
      var hasTransition = false;

      for (var i = 0; i < PRIMARY_STATES_KEYS.length; i++) {
        var key = PRIMARY_STATES_KEYS[i];
        var propNeedsTransition = transition && DEFAULT_ANIMATABLE_MAP[key];

        if (state && state[key] != null) {
          if (propNeedsTransition) {
            hasTransition = true;
            transitionTarget[key] = state[key];
          } else {
            this[key] = state[key];
          }
        } else if (needsRestoreToNormal) {
          if (normalState[key] != null) {
            if (propNeedsTransition) {
              hasTransition = true;
              transitionTarget[key] = normalState[key];
            } else {
              this[key] = normalState[key];
            }
          }
        }
      }

      if (!transition) {
        for (var i = 0; i < this.animators.length; i++) {
          var animator = this.animators[i];
          var targetName = animator.targetName;

          animator.__changeFinalValue(targetName ? (state || normalState)[targetName] : state || normalState);
        }
      }

      if (hasTransition) {
        this._transitionState(stateName, transitionTarget, animationCfg);
      }
    };

    Element.prototype._attachComponent = function (componentEl) {
      if (componentEl.__zr && !componentEl.__hostTarget) {
        throw new Error('Text element has been added to zrender.');
      }

      if (componentEl === this) {
        throw new Error('Recursive component attachment.');
      }

      var zr = this.__zr;

      if (zr) {
        componentEl.addSelfToZr(zr);
      }

      componentEl.__zr = zr;
      componentEl.__hostTarget = this;
    };

    Element.prototype._detachComponent = function (componentEl) {
      if (componentEl.__zr) {
        componentEl.removeSelfFromZr(componentEl.__zr);
      }

      componentEl.__zr = null;
      componentEl.__hostTarget = null;
    };

    Element.prototype.getClipPath = function () {
      return this._clipPath;
    };

    Element.prototype.setClipPath = function (clipPath) {
      if (this._clipPath && this._clipPath !== clipPath) {
        this.removeClipPath();
      }

      this._attachComponent(clipPath);

      this._clipPath = clipPath;
      this.markRedraw();
    };

    Element.prototype.removeClipPath = function () {
      var clipPath = this._clipPath;

      if (clipPath) {
        this._detachComponent(clipPath);

        this._clipPath = null;
        this.markRedraw();
      }
    };

    Element.prototype.getTextContent = function () {
      return this._textContent;
    };

    Element.prototype.setTextContent = function (textEl) {
      var previousTextContent = this._textContent;

      if (previousTextContent === textEl) {
        return;
      }

      if (previousTextContent && previousTextContent !== textEl) {
        this.removeTextContent();
      }

      if (textEl.__zr && !textEl.__hostTarget) {
        throw new Error('Text element has been added to zrender.');
      }

      textEl.attachedTransform = new Transformable();

      this._attachComponent(textEl);

      this._textContent = textEl;
      this.markRedraw();
    };

    Element.prototype.setTextConfig = function (cfg) {
      if (!this.textConfig) {
        this.textConfig = {};
      }

      extend(this.textConfig, cfg);
      this.markRedraw();
    };

    Element.prototype.removeTextContent = function () {
      var textEl = this._textContent;

      if (textEl) {
        textEl.attachedTransform = null;

        this._detachComponent(textEl);

        this._textContent = null;
        this._innerTextDefaultStyle = null;
        this.markRedraw();
      }
    };

    Element.prototype.getTextGuideLine = function () {
      return this._textGuide;
    };

    Element.prototype.setTextGuideLine = function (guideLine) {
      if (this._textGuide && this._textGuide !== guideLine) {
        this.removeTextGuideLine();
      }

      this._attachComponent(guideLine);

      this._textGuide = guideLine;
      this.markRedraw();
    };

    Element.prototype.removeTextGuideLine = function () {
      var textGuide = this._textGuide;

      if (textGuide) {
        this._detachComponent(textGuide);

        this._textGuide = null;
        this.markRedraw();
      }
    };

    Element.prototype.markRedraw = function () {
      this.__dirty |= Element.REDARAW_BIT;
      var zr = this.__zr;

      if (zr) {
        if (this.__inHover) {
          zr.refreshHover();
        } else {
          zr.refresh();
        }
      }

      if (this.__hostTarget) {
        this.__hostTarget.markRedraw();
      }
    };

    Element.prototype.dirty = function () {
      this.markRedraw();
    };

    Element.prototype._toggleHoverLayerFlag = function (inHover) {
      this.__inHover = inHover;
      var textContent = this._textContent;
      var textGuide = this._textGuide;

      if (textContent) {
        textContent.__inHover = inHover;
      }

      if (textGuide) {
        textGuide.__inHover = inHover;
      }
    };

    Element.prototype.addSelfToZr = function (zr) {
      this.__zr = zr;
      var animators = this.animators;

      if (animators) {
        for (var i = 0; i < animators.length; i++) {
          zr.animation.addAnimator(animators[i]);
        }
      }

      if (this._clipPath) {
        this._clipPath.addSelfToZr(zr);
      }

      if (this._textContent) {
        this._textContent.addSelfToZr(zr);
      }

      if (this._textGuide) {
        this._textGuide.addSelfToZr(zr);
      }
    };

    Element.prototype.removeSelfFromZr = function (zr) {
      this.__zr = null;
      var animators = this.animators;

      if (animators) {
        for (var i = 0; i < animators.length; i++) {
          zr.animation.removeAnimator(animators[i]);
        }
      }

      if (this._clipPath) {
        this._clipPath.removeSelfFromZr(zr);
      }

      if (this._textContent) {
        this._textContent.removeSelfFromZr(zr);
      }

      if (this._textGuide) {
        this._textGuide.removeSelfFromZr(zr);
      }
    };

    Element.prototype.animate = function (key, loop) {
      var target = key ? this[key] : this;

      if (!target) {
        logError('Property "' + key + '" is not existed in element ' + this.id);
        return;
      }

      var animator = new Animator(target, loop);
      this.addAnimator(animator, key);
      return animator;
    };

    Element.prototype.addAnimator = function (animator, key) {
      var zr = this.__zr;
      var el = this;
      animator.during(function () {
        el.updateDuringAnimation(key);
      }).done(function () {
        var animators = el.animators;
        var idx = indexOf(animators, animator);

        if (idx >= 0) {
          animators.splice(idx, 1);
        }
      });
      this.animators.push(animator);

      if (zr) {
        zr.animation.addAnimator(animator);
      }

      zr && zr.wakeUp();
    };

    Element.prototype.updateDuringAnimation = function (key) {
      this.markRedraw();
    };

    Element.prototype.stopAnimation = function (scope, forwardToLast) {
      var animators = this.animators;
      var len = animators.length;
      var leftAnimators = [];

      for (var i = 0; i < len; i++) {
        var animator = animators[i];

        if (!scope || scope === animator.scope) {
          animator.stop(forwardToLast);
        } else {
          leftAnimators.push(animator);
        }
      }

      this.animators = leftAnimators;
      return this;
    };

    Element.prototype.animateTo = function (target, cfg, animationProps) {
      animateTo(this, target, cfg, animationProps);
    };

    Element.prototype.animateFrom = function (target, cfg, animationProps) {
      animateTo(this, target, cfg, animationProps, true);
    };

    Element.prototype._transitionState = function (stateName, target, cfg, animationProps) {
      var animators = animateTo(this, target, cfg, animationProps);

      for (var i = 0; i < animators.length; i++) {
        animators[i].__fromStateTransition = stateName;
      }
    };

    Element.prototype.getBoundingRect = function () {
      return null;
    };

    Element.REDARAW_BIT = 1;

    Element.initDefaultProps = function () {
      var elProto = Element.prototype;
      elProto.type = 'element';
      elProto.name = '';
      elProto.ignore = false;
      elProto.silent = false;
      elProto.isGroup = false;
      elProto.draggable = false;
      elProto.dragging = false;
      elProto.__inHover = false;
      elProto.__dirty = Element.REDARAW_BIT;
      var logs = {};

      function logDeprecatedError(key, xKey, yKey) {
        if (!logs[key + xKey + yKey]) {
          console.warn("DEPRECATED: '" + key + "' has been deprecated. use '" + xKey + "', '" + yKey + "' instead");
          logs[key + xKey + yKey] = true;
        }
      }

      function createLegacyProperty(key, privateKey, xKey, yKey) {
        Object.defineProperty(elProto, key, {
          get: function () {
            logDeprecatedError(key, xKey, yKey);

            if (!this[privateKey]) {
              var pos = this[privateKey] = [];
              enhanceArray(this, pos);
            }

            return this[privateKey];
          },
          set: function (pos) {
            logDeprecatedError(key, xKey, yKey);
            this[xKey] = pos[0];
            this[yKey] = pos[1];
            this[privateKey] = pos;
            enhanceArray(this, pos);
          }
        });

        function enhanceArray(self, pos) {
          Object.defineProperty(pos, 0, {
            get: function () {
              return self[xKey];
            },
            set: function (val) {
              self[xKey] = val;
            }
          });
          Object.defineProperty(pos, 1, {
            get: function () {
              return self[yKey];
            },
            set: function (val) {
              self[yKey] = val;
            }
          });
        }
      }

      if (Object.defineProperty && (!env.browser.ie || env.browser.version > 8)) {
        createLegacyProperty('position', '_legacyPos', 'x', 'y');
        createLegacyProperty('scale', '_legacyScale', 'scaleX', 'scaleY');
        createLegacyProperty('origin', '_legacyOrigin', 'originX', 'originY');
      }
    }();

    return Element;
  }();

  mixin(Element, Eventful);
  mixin(Element, Transformable);

  function animateTo(animatable, target, cfg, animationProps, reverse) {
    cfg = cfg || {};
    var animators = [];
    animateToShallow(animatable, '', animatable, target, cfg, animationProps, animators, reverse);
    var count = animators.length;

    function done() {
      count--;

      if (!count) {
        cfg.done && cfg.done();
      }
    }

    if (!count) {
      cfg.done && cfg.done();
    }

    if (animators.length > 0 && typeof cfg.during === 'function') {
      animators[0].during(function (target, percent) {
        cfg.during(percent);
      });
    }

    for (var i = 0; i < animators.length; i++) {
      animators[i].done(done).start(cfg.easing, cfg.force);
    }

    return animators;
  }

  function copyArrShallow(source, target, len) {
    for (var i = 0; i < len; i++) {
      source[i] = target[i];
    }
  }

  function is2DArray(value) {
    return isArrayLike(value[0]);
  }

  function copyValue(target, source, key) {
    if (isArrayLike(source[key])) {
      if (!isArrayLike(target[key])) {
        target[key] = [];
      }

      var sourceArr = source[key];
      var targetArr = target[key];
      var len0 = sourceArr.length;

      if (is2DArray(sourceArr)) {
        var len1 = sourceArr[0].length;

        for (var i = 0; i < len0; i++) {
          if (!targetArr[i]) {
            targetArr[i] = Array.prototype.slice.call(sourceArr[i]);
          } else {
            copyArrShallow(targetArr[i], sourceArr[i], len1);
          }
        }
      } else {
        copyArrShallow(targetArr, sourceArr, len0);
      }

      targetArr.length = sourceArr.length;
    } else {
      target[key] = source[key];
    }
  }

  function animateToShallow(animatable, topKey, source, target, cfg, animationProps, animators, reverse) {
    var animatableKeys = [];
    var changedKeys = [];
    var targetKeys = keys(target);
    var duration = cfg.duration;
    var delay = cfg.delay;
    var additive = cfg.additive;
    var setToFinal = cfg.setToFinal;
    var animateAll = !isObject(animationProps);

    for (var k = 0; k < targetKeys.length; k++) {
      var innerKey = targetKeys[k];

      if (source[innerKey] != null && target[innerKey] != null && (animateAll || animationProps[innerKey])) {
        if (isObject(target[innerKey]) && !isArrayLike(target[innerKey])) {
          if (topKey) {
            if (!reverse) {
              source[innerKey] = target[innerKey];
              animatable.updateDuringAnimation(topKey);
            }

            continue;
          }

          animateToShallow(animatable, innerKey, source[innerKey], target[innerKey], cfg, animationProps && animationProps[innerKey], animators, reverse);
        } else {
          animatableKeys.push(innerKey);
          changedKeys.push(innerKey);
        }
      } else if (!reverse) {
        source[innerKey] = target[innerKey];
        animatable.updateDuringAnimation(topKey);
        changedKeys.push(innerKey);
      }
    }

    var keyLen = animatableKeys.length;

    if (keyLen > 0 || cfg.force) {
      var existsAnimators = animatable.animators;
      var existsAnimatorsOnSameTarget = [];

      for (var i = 0; i < existsAnimators.length; i++) {
        if (existsAnimators[i].targetName === topKey) {
          existsAnimatorsOnSameTarget.push(existsAnimators[i]);
        }
      }

      if (!additive && existsAnimatorsOnSameTarget.length) {
        for (var i = 0; i < existsAnimatorsOnSameTarget.length; i++) {
          var allAborted = existsAnimatorsOnSameTarget[i].stopTracks(changedKeys);

          if (allAborted) {
            var idx = indexOf(existsAnimators, existsAnimatorsOnSameTarget[i]);
            existsAnimators.splice(idx, 1);
          }
        }
      }

      var revertedSource = void 0;
      var reversedTarget = void 0;
      var sourceClone = void 0;

      if (reverse) {
        reversedTarget = {};

        if (setToFinal) {
          revertedSource = {};
        }

        for (var i = 0; i < keyLen; i++) {
          var innerKey = animatableKeys[i];
          reversedTarget[innerKey] = source[innerKey];

          if (setToFinal) {
            revertedSource[innerKey] = target[innerKey];
          } else {
            source[innerKey] = target[innerKey];
          }
        }
      } else if (setToFinal) {
        sourceClone = {};

        for (var i = 0; i < keyLen; i++) {
          var innerKey = animatableKeys[i];
          sourceClone[innerKey] = cloneValue(source[innerKey]);
          copyValue(source, target, innerKey);
        }
      }

      var animator = new Animator(source, false, additive ? existsAnimatorsOnSameTarget : null);
      animator.targetName = topKey;

      if (cfg.scope) {
        animator.scope = cfg.scope;
      }

      if (setToFinal && revertedSource) {
        animator.whenWithKeys(0, revertedSource, animatableKeys);
      }

      if (sourceClone) {
        animator.whenWithKeys(0, sourceClone, animatableKeys);
      }

      animator.whenWithKeys(duration == null ? 500 : duration, reverse ? reversedTarget : target, animatableKeys).delay(delay || 0);
      animatable.addAnimator(animator, topKey);
      animators.push(animator);
    }
  }

  var STYLE_MAGIC_KEY = '__zr_style_' + Math.round(Math.random() * 10);
  var DEFAULT_COMMON_STYLE = {
    shadowBlur: 0,
    shadowOffsetX: 0,
    shadowOffsetY: 0,
    shadowColor: '#000',
    opacity: 1,
    blend: 'source-over'
  };
  var DEFAULT_COMMON_ANIMATION_PROPS = {
    style: {
      shadowBlur: true,
      shadowOffsetX: true,
      shadowOffsetY: true,
      shadowColor: true,
      opacity: true
    }
  };
  DEFAULT_COMMON_STYLE[STYLE_MAGIC_KEY] = true;
  var PRIMARY_STATES_KEYS$1 = ['z', 'z2', 'invisible'];

  var Displayable = function (_super) {
    __extends(Displayable, _super);

    function Displayable(props) {
      return _super.call(this, props) || this;
    }

    Displayable.prototype._init = function (props) {
      var keysArr = keys(props);

      for (var i = 0; i < keysArr.length; i++) {
        var key = keysArr[i];

        if (key === 'style') {
          this.useStyle(props[key]);
        } else {
          _super.prototype.attrKV.call(this, key, props[key]);
        }
      }

      if (!this.style) {
        this.useStyle({});
      }
    };

    Displayable.prototype.beforeBrush = function () {};

    Displayable.prototype.afterBrush = function () {};

    Displayable.prototype.innerBeforeBrush = function () {};

    Displayable.prototype.innerAfterBrush = function () {};

    Displayable.prototype.contain = function (x, y) {
      return this.rectContain(x, y);
    };

    Displayable.prototype.traverse = function (cb, context) {
      cb.call(context, this);
    };

    Displayable.prototype.rectContain = function (x, y) {
      var coord = this.transformCoordToLocal(x, y);
      var rect = this.getBoundingRect();
      return rect.contain(coord[0], coord[1]);
    };

    Displayable.prototype.animateStyle = function (loop) {
      return this.animate('style', loop);
    };

    Displayable.prototype.updateDuringAnimation = function (targetKey) {
      if (targetKey === 'style') {
        this.dirtyStyle();
      } else {
        this.markRedraw();
      }
    };

    Displayable.prototype.attrKV = function (key, value) {
      if (key !== 'style') {
        _super.prototype.attrKV.call(this, key, value);
      } else {
        if (!this.style) {
          this.useStyle(value);
        } else {
          this.setStyle(value);
        }
      }
    };

    Displayable.prototype.setStyle = function (keyOrObj, value) {
      if (typeof keyOrObj === 'string') {
        this.style[keyOrObj] = value;
      } else {
        extend(this.style, keyOrObj);
      }

      this.dirtyStyle();
      return this;
    };

    Displayable.prototype.dirtyStyle = function () {
      this.markRedraw();
      this.__dirty |= Displayable.STYLE_CHANGED_BIT;

      if (this._rect) {
        this._rect = null;
      }
    };

    Displayable.prototype.dirty = function () {
      this.dirtyStyle();
    };

    Displayable.prototype.styleChanged = function () {
      return !!(this.__dirty & Displayable.STYLE_CHANGED_BIT);
    };

    Displayable.prototype.styleUpdated = function () {
      this.__dirty &= ~Displayable.STYLE_CHANGED_BIT;
    };

    Displayable.prototype.createStyle = function (obj) {
      return createObject(DEFAULT_COMMON_STYLE, obj);
    };

    Displayable.prototype.useStyle = function (obj) {
      if (!obj[STYLE_MAGIC_KEY]) {
        obj = this.createStyle(obj);
      }

      if (this.__inHover) {
        this.__hoverStyle = obj;
      } else {
        this.style = obj;
      }

      this.dirtyStyle();
    };

    Displayable.prototype.isStyleObject = function (obj) {
      return obj[STYLE_MAGIC_KEY];
    };

    Displayable.prototype._innerSaveToNormal = function (toState) {
      _super.prototype._innerSaveToNormal.call(this, toState);

      var normalState = this._normalState;

      if (toState.style && !normalState.style) {
        normalState.style = this._mergeStyle(this.createStyle(), this.style);
      }

      this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS$1);
    };

    Displayable.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
      _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg);

      var needsRestoreToNormal = !(state && keepCurrentStates);
      var targetStyle;

      if (state && state.style) {
        if (transition) {
          if (keepCurrentStates) {
            targetStyle = state.style;
          } else {
            targetStyle = this._mergeStyle(this.createStyle(), normalState.style);

            this._mergeStyle(targetStyle, state.style);
          }
        } else {
          targetStyle = this._mergeStyle(this.createStyle(), keepCurrentStates ? this.style : normalState.style);

          this._mergeStyle(targetStyle, state.style);
        }
      } else if (needsRestoreToNormal) {
        targetStyle = normalState.style;
      }

      if (targetStyle) {
        if (transition) {
          var sourceStyle = this.style;
          this.style = this.createStyle(needsRestoreToNormal ? {} : sourceStyle);

          if (needsRestoreToNormal) {
            var changedKeys = keys(sourceStyle);

            for (var i = 0; i < changedKeys.length; i++) {
              var key = changedKeys[i];

              if (key in targetStyle) {
                targetStyle[key] = targetStyle[key];
                this.style[key] = sourceStyle[key];
              }
            }
          }

          var targetKeys = keys(targetStyle);

          for (var i = 0; i < targetKeys.length; i++) {
            var key = targetKeys[i];
            this.style[key] = this.style[key];
          }

          this._transitionState(stateName, {
            style: targetStyle
          }, animationCfg, this._getAnimationStyleProps());
        } else {
          this.useStyle(targetStyle);
        }
      }

      for (var i = 0; i < PRIMARY_STATES_KEYS$1.length; i++) {
        var key = PRIMARY_STATES_KEYS$1[i];

        if (state && state[key] != null) {
          this[key] = state[key];
        } else if (needsRestoreToNormal) {
          if (normalState[key] != null) {
            this[key] = normalState[key];
          }
        }
      }
    };

    Displayable.prototype._mergeStates = function (states) {
      var mergedState = _super.prototype._mergeStates.call(this, states);

      var mergedStyle;

      for (var i = 0; i < states.length; i++) {
        var state = states[i];

        if (state.style) {
          mergedStyle = mergedStyle || {};

          this._mergeStyle(mergedStyle, state.style);
        }
      }

      if (mergedStyle) {
        mergedState.style = mergedStyle;
      }

      return mergedState;
    };

    Displayable.prototype._mergeStyle = function (targetStyle, sourceStyle) {
      extend(targetStyle, sourceStyle);
      return targetStyle;
    };

    Displayable.prototype._getAnimationStyleProps = function () {
      return DEFAULT_COMMON_ANIMATION_PROPS;
    };

    Displayable.STYLE_CHANGED_BIT = 2;

    Displayable.initDefaultProps = function () {
      var dispProto = Displayable.prototype;
      dispProto.type = 'displayable';
      dispProto.invisible = false;
      dispProto.z = 0;
      dispProto.z2 = 0;
      dispProto.zlevel = 0;
      dispProto.culling = false;
      dispProto.cursor = 'pointer';
      dispProto.rectHover = false;
      dispProto.incremental = false;
      dispProto._rect = null;
      dispProto.__dirty = Element.REDARAW_BIT | Displayable.STYLE_CHANGED_BIT;
    }();

    return Displayable;
  }(Element);

  var mathPow = Math.pow;
  var mathSqrt = Math.sqrt;
  var EPSILON$1 = 1e-8;
  var EPSILON_NUMERIC = 1e-4;
  var THREE_SQRT = mathSqrt(3);
  var ONE_THIRD = 1 / 3;

  var _v0 = create();

  var _v1 = create();

  var _v2 = create();

  function isAroundZero(val) {
    return val > -EPSILON$1 && val < EPSILON$1;
  }

  function isNotAroundZero$1(val) {
    return val > EPSILON$1 || val < -EPSILON$1;
  }

  function cubicAt(p0, p1, p2, p3, t) {
    var onet = 1 - t;
    return onet * onet * (onet * p0 + 3 * t * p1) + t * t * (t * p3 + 3 * onet * p2);
  }

  function cubicDerivativeAt(p0, p1, p2, p3, t) {
    var onet = 1 - t;
    return 3 * (((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet + (p3 - p2) * t * t);
  }

  function cubicRootAt(p0, p1, p2, p3, val, roots) {
    var a = p3 + 3 * (p1 - p2) - p0;
    var b = 3 * (p2 - p1 * 2 + p0);
    var c = 3 * (p1 - p0);
    var d = p0 - val;
    var A = b * b - 3 * a * c;
    var B = b * c - 9 * a * d;
    var C = c * c - 3 * b * d;
    var n = 0;

    if (isAroundZero(A) && isAroundZero(B)) {
      if (isAroundZero(b)) {
        roots[0] = 0;
      } else {
        var t1 = -c / b;

        if (t1 >= 0 && t1 <= 1) {
          roots[n++] = t1;
        }
      }
    } else {
      var disc = B * B - 4 * A * C;

      if (isAroundZero(disc)) {
        var K = B / A;
        var t1 = -b / a + K;
        var t2 = -K / 2;

        if (t1 >= 0 && t1 <= 1) {
          roots[n++] = t1;
        }

        if (t2 >= 0 && t2 <= 1) {
          roots[n++] = t2;
        }
      } else if (disc > 0) {
        var discSqrt = mathSqrt(disc);
        var Y1 = A * b + 1.5 * a * (-B + discSqrt);
        var Y2 = A * b + 1.5 * a * (-B - discSqrt);

        if (Y1 < 0) {
          Y1 = -mathPow(-Y1, ONE_THIRD);
        } else {
          Y1 = mathPow(Y1, ONE_THIRD);
        }

        if (Y2 < 0) {
          Y2 = -mathPow(-Y2, ONE_THIRD);
        } else {
          Y2 = mathPow(Y2, ONE_THIRD);
        }

        var t1 = (-b - (Y1 + Y2)) / (3 * a);

        if (t1 >= 0 && t1 <= 1) {
          roots[n++] = t1;
        }
      } else {
        var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt(A * A * A));
        var theta = Math.acos(T) / 3;
        var ASqrt = mathSqrt(A);
        var tmp = Math.cos(theta);
        var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);
        var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);
        var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);

        if (t1 >= 0 && t1 <= 1) {
          roots[n++] = t1;
        }

        if (t2 >= 0 && t2 <= 1) {
          roots[n++] = t2;
        }

        if (t3 >= 0 && t3 <= 1) {
          roots[n++] = t3;
        }
      }
    }

    return n;
  }

  function cubicExtrema(p0, p1, p2, p3, extrema) {
    var b = 6 * p2 - 12 * p1 + 6 * p0;
    var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;
    var c = 3 * p1 - 3 * p0;
    var n = 0;

    if (isAroundZero(a)) {
      if (isNotAroundZero$1(b)) {
        var t1 = -c / b;

        if (t1 >= 0 && t1 <= 1) {
          extrema[n++] = t1;
        }
      }
    } else {
      var disc = b * b - 4 * a * c;

      if (isAroundZero(disc)) {
        extrema[0] = -b / (2 * a);
      } else if (disc > 0) {
        var discSqrt = mathSqrt(disc);
        var t1 = (-b + discSqrt) / (2 * a);
        var t2 = (-b - discSqrt) / (2 * a);

        if (t1 >= 0 && t1 <= 1) {
          extrema[n++] = t1;
        }

        if (t2 >= 0 && t2 <= 1) {
          extrema[n++] = t2;
        }
      }
    }

    return n;
  }

  function cubicSubdivide(p0, p1, p2, p3, t, out) {
    var p01 = (p1 - p0) * t + p0;
    var p12 = (p2 - p1) * t + p1;
    var p23 = (p3 - p2) * t + p2;
    var p012 = (p12 - p01) * t + p01;
    var p123 = (p23 - p12) * t + p12;
    var p0123 = (p123 - p012) * t + p012;
    out[0] = p0;
    out[1] = p01;
    out[2] = p012;
    out[3] = p0123;
    out[4] = p0123;
    out[5] = p123;
    out[6] = p23;
    out[7] = p3;
  }

  function cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, out) {
    var t;
    var interval = 0.005;
    var d = Infinity;
    var prev;
    var next;
    var d1;
    var d2;
    _v0[0] = x;
    _v0[1] = y;

    for (var _t = 0; _t < 1; _t += 0.05) {
      _v1[0] = cubicAt(x0, x1, x2, x3, _t);
      _v1[1] = cubicAt(y0, y1, y2, y3, _t);
      d1 = distSquare(_v0, _v1);

      if (d1 < d) {
        t = _t;
        d = d1;
      }
    }

    d = Infinity;

    for (var i = 0; i < 32; i++) {
      if (interval < EPSILON_NUMERIC) {
        break;
      }

      prev = t - interval;
      next = t + interval;
      _v1[0] = cubicAt(x0, x1, x2, x3, prev);
      _v1[1] = cubicAt(y0, y1, y2, y3, prev);
      d1 = distSquare(_v1, _v0);

      if (prev >= 0 && d1 < d) {
        t = prev;
        d = d1;
      } else {
        _v2[0] = cubicAt(x0, x1, x2, x3, next);
        _v2[1] = cubicAt(y0, y1, y2, y3, next);
        d2 = distSquare(_v2, _v0);

        if (next <= 1 && d2 < d) {
          t = next;
          d = d2;
        } else {
          interval *= 0.5;
        }
      }
    }

    if (out) {
      out[0] = cubicAt(x0, x1, x2, x3, t);
      out[1] = cubicAt(y0, y1, y2, y3, t);
    }

    return mathSqrt(d);
  }

  function cubicLength(x0, y0, x1, y1, x2, y2, x3, y3, iteration) {
    var px = x0;
    var py = y0;
    var d = 0;
    var step = 1 / iteration;

    for (var i = 1; i <= iteration; i++) {
      var t = i * step;
      var x = cubicAt(x0, x1, x2, x3, t);
      var y = cubicAt(y0, y1, y2, y3, t);
      var dx = x - px;
      var dy = y - py;
      d += Math.sqrt(dx * dx + dy * dy);
      px = x;
      py = y;
    }

    return d;
  }

  function quadraticAt(p0, p1, p2, t) {
    var onet = 1 - t;
    return onet * (onet * p0 + 2 * t * p1) + t * t * p2;
  }

  function quadraticDerivativeAt(p0, p1, p2, t) {
    return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));
  }

  function quadraticRootAt(p0, p1, p2, val, roots) {
    var a = p0 - 2 * p1 + p2;
    var b = 2 * (p1 - p0);
    var c = p0 - val;
    var n = 0;

    if (isAroundZero(a)) {
      if (isNotAroundZero$1(b)) {
        var t1 = -c / b;

        if (t1 >= 0 && t1 <= 1) {
          roots[n++] = t1;
        }
      }
    } else {
      var disc = b * b - 4 * a * c;

      if (isAroundZero(disc)) {
        var t1 = -b / (2 * a);

        if (t1 >= 0 && t1 <= 1) {
          roots[n++] = t1;
        }
      } else if (disc > 0) {
        var discSqrt = mathSqrt(disc);
        var t1 = (-b + discSqrt) / (2 * a);
        var t2 = (-b - discSqrt) / (2 * a);

        if (t1 >= 0 && t1 <= 1) {
          roots[n++] = t1;
        }

        if (t2 >= 0 && t2 <= 1) {
          roots[n++] = t2;
        }
      }
    }

    return n;
  }

  function quadraticExtremum(p0, p1, p2) {
    var divider = p0 + p2 - 2 * p1;

    if (divider === 0) {
      return 0.5;
    } else {
      return (p0 - p1) / divider;
    }
  }

  function quadraticSubdivide(p0, p1, p2, t, out) {
    var p01 = (p1 - p0) * t + p0;
    var p12 = (p2 - p1) * t + p1;
    var p012 = (p12 - p01) * t + p01;
    out[0] = p0;
    out[1] = p01;
    out[2] = p012;
    out[3] = p012;
    out[4] = p12;
    out[5] = p2;
  }

  function quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, out) {
    var t;
    var interval = 0.005;
    var d = Infinity;
    _v0[0] = x;
    _v0[1] = y;

    for (var _t = 0; _t < 1; _t += 0.05) {
      _v1[0] = quadraticAt(x0, x1, x2, _t);
      _v1[1] = quadraticAt(y0, y1, y2, _t);
      var d1 = distSquare(_v0, _v1);

      if (d1 < d) {
        t = _t;
        d = d1;
      }
    }

    d = Infinity;

    for (var i = 0; i < 32; i++) {
      if (interval < EPSILON_NUMERIC) {
        break;
      }

      var prev = t - interval;
      var next = t + interval;
      _v1[0] = quadraticAt(x0, x1, x2, prev);
      _v1[1] = quadraticAt(y0, y1, y2, prev);
      var d1 = distSquare(_v1, _v0);

      if (prev >= 0 && d1 < d) {
        t = prev;
        d = d1;
      } else {
        _v2[0] = quadraticAt(x0, x1, x2, next);
        _v2[1] = quadraticAt(y0, y1, y2, next);
        var d2 = distSquare(_v2, _v0);

        if (next <= 1 && d2 < d) {
          t = next;
          d = d2;
        } else {
          interval *= 0.5;
        }
      }
    }

    if (out) {
      out[0] = quadraticAt(x0, x1, x2, t);
      out[1] = quadraticAt(y0, y1, y2, t);
    }

    return mathSqrt(d);
  }

  function quadraticLength(x0, y0, x1, y1, x2, y2, iteration) {
    var px = x0;
    var py = y0;
    var d = 0;
    var step = 1 / iteration;

    for (var i = 1; i <= iteration; i++) {
      var t = i * step;
      var x = quadraticAt(x0, x1, x2, t);
      var y = quadraticAt(y0, y1, y2, t);
      var dx = x - px;
      var dy = y - py;
      d += Math.sqrt(dx * dx + dy * dy);
      px = x;
      py = y;
    }

    return d;
  }

  var mathMin$1 = Math.min;
  var mathMax$1 = Math.max;
  var mathSin = Math.sin;
  var mathCos = Math.cos;
  var PI2 = Math.PI * 2;
  var start = create();
  var end = create();
  var extremity = create();

  function fromPoints(points, min, max) {
    if (points.length === 0) {
      return;
    }

    var p = points[0];
    var left = p[0];
    var right = p[0];
    var top = p[1];
    var bottom = p[1];

    for (var i = 1; i < points.length; i++) {
      p = points[i];
      left = mathMin$1(left, p[0]);
      right = mathMax$1(right, p[0]);
      top = mathMin$1(top, p[1]);
      bottom = mathMax$1(bottom, p[1]);
    }

    min[0] = left;
    min[1] = top;
    max[0] = right;
    max[1] = bottom;
  }

  function fromLine(x0, y0, x1, y1, min, max) {
    min[0] = mathMin$1(x0, x1);
    min[1] = mathMin$1(y0, y1);
    max[0] = mathMax$1(x0, x1);
    max[1] = mathMax$1(y0, y1);
  }

  var xDim = [];
  var yDim = [];

  function fromCubic(x0, y0, x1, y1, x2, y2, x3, y3, min, max) {
    var cubicExtrema$1 = cubicExtrema;
    var cubicAt$1 = cubicAt;
    var n = cubicExtrema$1(x0, x1, x2, x3, xDim);
    min[0] = Infinity;
    min[1] = Infinity;
    max[0] = -Infinity;
    max[1] = -Infinity;

    for (var i = 0; i < n; i++) {
      var x = cubicAt$1(x0, x1, x2, x3, xDim[i]);
      min[0] = mathMin$1(x, min[0]);
      max[0] = mathMax$1(x, max[0]);
    }

    n = cubicExtrema$1(y0, y1, y2, y3, yDim);

    for (var i = 0; i < n; i++) {
      var y = cubicAt$1(y0, y1, y2, y3, yDim[i]);
      min[1] = mathMin$1(y, min[1]);
      max[1] = mathMax$1(y, max[1]);
    }

    min[0] = mathMin$1(x0, min[0]);
    max[0] = mathMax$1(x0, max[0]);
    min[0] = mathMin$1(x3, min[0]);
    max[0] = mathMax$1(x3, max[0]);
    min[1] = mathMin$1(y0, min[1]);
    max[1] = mathMax$1(y0, max[1]);
    min[1] = mathMin$1(y3, min[1]);
    max[1] = mathMax$1(y3, max[1]);
  }

  function fromQuadratic(x0, y0, x1, y1, x2, y2, min, max) {
    var quadraticExtremum$1 = quadraticExtremum;
    var quadraticAt$1 = quadraticAt;
    var tx = mathMax$1(mathMin$1(quadraticExtremum$1(x0, x1, x2), 1), 0);
    var ty = mathMax$1(mathMin$1(quadraticExtremum$1(y0, y1, y2), 1), 0);
    var x = quadraticAt$1(x0, x1, x2, tx);
    var y = quadraticAt$1(y0, y1, y2, ty);
    min[0] = mathMin$1(x0, x2, x);
    min[1] = mathMin$1(y0, y2, y);
    max[0] = mathMax$1(x0, x2, x);
    max[1] = mathMax$1(y0, y2, y);
  }

  function fromArc(x, y, rx, ry, startAngle, endAngle, anticlockwise, min$1, max$1) {
    var vec2Min = min;
    var vec2Max = max;
    var diff = Math.abs(startAngle - endAngle);

    if (diff % PI2 < 1e-4 && diff > 1e-4) {
      min$1[0] = x - rx;
      min$1[1] = y - ry;
      max$1[0] = x + rx;
      max$1[1] = y + ry;
      return;
    }

    start[0] = mathCos(startAngle) * rx + x;
    start[1] = mathSin(startAngle) * ry + y;
    end[0] = mathCos(endAngle) * rx + x;
    end[1] = mathSin(endAngle) * ry + y;
    vec2Min(min$1, start, end);
    vec2Max(max$1, start, end);
    startAngle = startAngle % PI2;

    if (startAngle < 0) {
      startAngle = startAngle + PI2;
    }

    endAngle = endAngle % PI2;

    if (endAngle < 0) {
      endAngle = endAngle + PI2;
    }

    if (startAngle > endAngle && !anticlockwise) {
      endAngle += PI2;
    } else if (startAngle < endAngle && anticlockwise) {
      startAngle += PI2;
    }

    if (anticlockwise) {
      var tmp = endAngle;
      endAngle = startAngle;
      startAngle = tmp;
    }

    for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {
      if (angle > startAngle) {
        extremity[0] = mathCos(angle) * rx + x;
        extremity[1] = mathSin(angle) * ry + y;
        vec2Min(min$1, extremity, min$1);
        vec2Max(max$1, extremity, max$1);
      }
    }
  }

  var CMD = {
    M: 1,
    L: 2,
    C: 3,
    Q: 4,
    A: 5,
    Z: 6,
    R: 7
  };
  var tmpOutX = [];
  var tmpOutY = [];
  var min$1 = [];
  var max$1 = [];
  var min2 = [];
  var max2 = [];
  var mathMin$2 = Math.min;
  var mathMax$2 = Math.max;
  var mathCos$1 = Math.cos;
  var mathSin$1 = Math.sin;
  var mathSqrt$1 = Math.sqrt;
  var mathAbs = Math.abs;
  var PI = Math.PI;
  var PI2$1 = PI * 2;
  var hasTypedArray = typeof Float32Array !== 'undefined';

  var PathProxy = function () {
    function PathProxy(notSaveData) {
      this.dpr = 1;
      this._xi = 0;
      this._yi = 0;
      this._x0 = 0;
      this._y0 = 0;
      this._len = 0;

      if (notSaveData) {
        this._saveData = false;
      }

      if (this._saveData) {
        this.data = [];
      }
    }

    PathProxy.prototype.setScale = function (sx, sy, segmentIgnoreThreshold) {
      segmentIgnoreThreshold = segmentIgnoreThreshold || 0;

      if (segmentIgnoreThreshold > 0) {
        this._ux = mathAbs(segmentIgnoreThreshold / devicePixelRatio / sx) || 0;
        this._uy = mathAbs(segmentIgnoreThreshold / devicePixelRatio / sy) || 0;
      }
    };

    PathProxy.prototype.setDPR = function (dpr) {
      this.dpr = dpr;
    };

    PathProxy.prototype.setContext = function (ctx) {
      this._ctx = ctx;
    };

    PathProxy.prototype.getContext = function () {
      return this._ctx;
    };

    PathProxy.prototype.beginPath = function () {
      this._ctx && this._ctx.beginPath();
      this.reset();
      return this;
    };

    PathProxy.prototype.reset = function () {
      if (this._saveData) {
        this._len = 0;
      }

      if (this._lineDash) {
        this._lineDash = null;
        this._dashOffset = 0;
      }

      if (this._pathSegLen) {
        this._pathSegLen = null;
        this._pathLen = 0;
      }
    };

    PathProxy.prototype.moveTo = function (x, y) {
      this.addData(CMD.M, x, y);
      this._ctx && this._ctx.moveTo(x, y);
      this._x0 = x;
      this._y0 = y;
      this._xi = x;
      this._yi = y;
      return this;
    };

    PathProxy.prototype.lineTo = function (x, y) {
      var exceedUnit = mathAbs(x - this._xi) > this._ux || mathAbs(y - this._yi) > this._uy || this._len < 5;
      this.addData(CMD.L, x, y);

      if (this._ctx && exceedUnit) {
        this._needsDash ? this._dashedLineTo(x, y) : this._ctx.lineTo(x, y);
      }

      if (exceedUnit) {
        this._xi = x;
        this._yi = y;
      }

      return this;
    };

    PathProxy.prototype.bezierCurveTo = function (x1, y1, x2, y2, x3, y3) {
      this.addData(CMD.C, x1, y1, x2, y2, x3, y3);

      if (this._ctx) {
        this._needsDash ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3) : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
      }

      this._xi = x3;
      this._yi = y3;
      return this;
    };

    PathProxy.prototype.quadraticCurveTo = function (x1, y1, x2, y2) {
      this.addData(CMD.Q, x1, y1, x2, y2);

      if (this._ctx) {
        this._needsDash ? this._dashedQuadraticTo(x1, y1, x2, y2) : this._ctx.quadraticCurveTo(x1, y1, x2, y2);
      }

      this._xi = x2;
      this._yi = y2;
      return this;
    };

    PathProxy.prototype.arc = function (cx, cy, r, startAngle, endAngle, anticlockwise) {
      var delta = endAngle - startAngle;
      endAngle = startAngle + delta;
      this.addData(CMD.A, cx, cy, r, r, startAngle, delta, 0, anticlockwise ? 0 : 1);
      this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);
      this._xi = mathCos$1(endAngle) * r + cx;
      this._yi = mathSin$1(endAngle) * r + cy;
      return this;
    };

    PathProxy.prototype.arcTo = function (x1, y1, x2, y2, radius) {
      if (this._ctx) {
        this._ctx.arcTo(x1, y1, x2, y2, radius);
      }

      return this;
    };

    PathProxy.prototype.rect = function (x, y, w, h) {
      this._ctx && this._ctx.rect(x, y, w, h);
      this.addData(CMD.R, x, y, w, h);
      return this;
    };

    PathProxy.prototype.closePath = function () {
      this.addData(CMD.Z);
      var ctx = this._ctx;
      var x0 = this._x0;
      var y0 = this._y0;

      if (ctx) {
        this._needsDash && this._dashedLineTo(x0, y0);
        ctx.closePath();
      }

      this._xi = x0;
      this._yi = y0;
      return this;
    };

    PathProxy.prototype.fill = function (ctx) {
      ctx && ctx.fill();
      this.toStatic();
    };

    PathProxy.prototype.stroke = function (ctx) {
      ctx && ctx.stroke();
      this.toStatic();
    };

    PathProxy.prototype.setLineDash = function (lineDash) {
      if (lineDash instanceof Array) {
        this._lineDash = lineDash;
        this._dashIdx = 0;
        var lineDashSum = 0;

        for (var i = 0; i < lineDash.length; i++) {
          lineDashSum += lineDash[i];
        }

        this._dashSum = lineDashSum;
        this._needsDash = true;
      } else {
        this._lineDash = null;
        this._needsDash = false;
      }

      return this;
    };

    PathProxy.prototype.setLineDashOffset = function (offset) {
      this._dashOffset = offset;
      return this;
    };

    PathProxy.prototype.len = function () {
      return this._len;
    };

    PathProxy.prototype.setData = function (data) {
      var len = data.length;

      if (!(this.data && this.data.length === len) && hasTypedArray) {
        this.data = new Float32Array(len);
      }

      for (var i = 0; i < len; i++) {
        this.data[i] = data[i];
      }

      this._len = len;
    };

    PathProxy.prototype.appendPath = function (path) {
      if (!(path instanceof Array)) {
        path = [path];
      }

      var len = path.length;
      var appendSize = 0;
      var offset = this._len;

      for (var i = 0; i < len; i++) {
        appendSize += path[i].len();
      }

      if (hasTypedArray && this.data instanceof Float32Array) {
        this.data = new Float32Array(offset + appendSize);
      }

      for (var i = 0; i < len; i++) {
        var appendPathData = path[i].data;

        for (var k = 0; k < appendPathData.length; k++) {
          this.data[offset++] = appendPathData[k];
        }
      }

      this._len = offset;
    };

    PathProxy.prototype.addData = function (cmd, a, b, c, d, e, f, g, h) {
      if (!this._saveData) {
        return;
      }

      var data = this.data;

      if (this._len + arguments.length > data.length) {
        this._expandData();

        data = this.data;
      }

      for (var i = 0; i < arguments.length; i++) {
        data[this._len++] = arguments[i];
      }
    };

    PathProxy.prototype._expandData = function () {
      if (!(this.data instanceof Array)) {
        var newData = [];

        for (var i = 0; i < this._len; i++) {
          newData[i] = this.data[i];
        }

        this.data = newData;
      }
    };

    PathProxy.prototype._dashedLineTo = function (x1, y1) {
      var dashSum = this._dashSum;
      var lineDash = this._lineDash;
      var ctx = this._ctx;
      var offset = this._dashOffset;
      var x0 = this._xi;
      var y0 = this._yi;
      var dx = x1 - x0;
      var dy = y1 - y0;
      var dist = mathSqrt$1(dx * dx + dy * dy);
      var x = x0;
      var y = y0;
      var nDash = lineDash.length;
      var dash;
      var idx;
      dx /= dist;
      dy /= dist;

      if (offset < 0) {
        offset = dashSum + offset;
      }

      offset %= dashSum;
      x -= offset * dx;
      y -= offset * dy;

      while (dx > 0 && x <= x1 || dx < 0 && x >= x1 || dx === 0 && (dy > 0 && y <= y1 || dy < 0 && y >= y1)) {
        idx = this._dashIdx;
        dash = lineDash[idx];
        x += dx * dash;
        y += dy * dash;
        this._dashIdx = (idx + 1) % nDash;

        if (dx > 0 && x < x0 || dx < 0 && x > x0 || dy > 0 && y < y0 || dy < 0 && y > y0) {
          continue;
        }

        ctx[idx % 2 ? 'moveTo' : 'lineTo'](dx >= 0 ? mathMin$2(x, x1) : mathMax$2(x, x1), dy >= 0 ? mathMin$2(y, y1) : mathMax$2(y, y1));
      }

      dx = x - x1;
      dy = y - y1;
      this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);
    };

    PathProxy.prototype._dashedBezierTo = function (x1, y1, x2, y2, x3, y3) {
      var ctx = this._ctx;
      var dashSum = this._dashSum;
      var offset = this._dashOffset;
      var lineDash = this._lineDash;
      var x0 = this._xi;
      var y0 = this._yi;
      var bezierLen = 0;
      var idx = this._dashIdx;
      var nDash = lineDash.length;
      var t;
      var dx;
      var dy;
      var x;
      var y;
      var tmpLen = 0;

      if (offset < 0) {
        offset = dashSum + offset;
      }

      offset %= dashSum;

      for (t = 0; t < 1; t += 0.1) {
        dx = cubicAt(x0, x1, x2, x3, t + 0.1) - cubicAt(x0, x1, x2, x3, t);
        dy = cubicAt(y0, y1, y2, y3, t + 0.1) - cubicAt(y0, y1, y2, y3, t);
        bezierLen += mathSqrt$1(dx * dx + dy * dy);
      }

      for (; idx < nDash; idx++) {
        tmpLen += lineDash[idx];

        if (tmpLen > offset) {
          break;
        }
      }

      t = (tmpLen - offset) / bezierLen;

      while (t <= 1) {
        x = cubicAt(x0, x1, x2, x3, t);
        y = cubicAt(y0, y1, y2, y3, t);
        idx % 2 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
        t += lineDash[idx] / bezierLen;
        idx = (idx + 1) % nDash;
      }

      idx % 2 !== 0 && ctx.lineTo(x3, y3);
      dx = x3 - x;
      dy = y3 - y;
      this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);
    };

    PathProxy.prototype._dashedQuadraticTo = function (x1, y1, x2, y2) {
      var x3 = x2;
      var y3 = y2;
      x2 = (x2 + 2 * x1) / 3;
      y2 = (y2 + 2 * y1) / 3;
      x1 = (this._xi + 2 * x1) / 3;
      y1 = (this._yi + 2 * y1) / 3;

      this._dashedBezierTo(x1, y1, x2, y2, x3, y3);
    };

    PathProxy.prototype.toStatic = function () {
      if (!this._saveData) {
        return;
      }

      var data = this.data;

      if (data instanceof Array) {
        data.length = this._len;

        if (hasTypedArray && this._len > 11) {
          this.data = new Float32Array(data);
        }
      }
    };

    PathProxy.prototype.getBoundingRect = function () {
      min$1[0] = min$1[1] = min2[0] = min2[1] = Number.MAX_VALUE;
      max$1[0] = max$1[1] = max2[0] = max2[1] = -Number.MAX_VALUE;
      var data = this.data;
      var xi = 0;
      var yi = 0;
      var x0 = 0;
      var y0 = 0;
      var i;

      for (i = 0; i < data.length;) {
        var cmd = data[i++];

        if (i === 1) {
          xi = data[i];
          yi = data[i + 1];
          x0 = xi;
          y0 = yi;
        }

        switch (cmd) {
          case CMD.M:
            xi = x0 = data[i++];
            yi = y0 = data[i++];
            min2[0] = x0;
            min2[1] = y0;
            max2[0] = x0;
            max2[1] = y0;
            break;

          case CMD.L:
            fromLine(xi, yi, data[i], data[i + 1], min2, max2);
            xi = data[i++];
            yi = data[i++];
            break;

          case CMD.C:
            fromCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], min2, max2);
            xi = data[i++];
            yi = data[i++];
            break;

          case CMD.Q:
            fromQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], min2, max2);
            xi = data[i++];
            yi = data[i++];
            break;

          case CMD.A:
            var cx = data[i++];
            var cy = data[i++];
            var rx = data[i++];
            var ry = data[i++];
            var startAngle = data[i++];
            var endAngle = data[i++] + startAngle;
            i += 1;
            var anticlockwise = 1 - data[i++];

            if (i === 1) {
              x0 = mathCos$1(startAngle) * rx + cx;
              y0 = mathSin$1(startAngle) * ry + cy;
            }

            fromArc(cx, cy, rx, ry, startAngle, endAngle, !!anticlockwise, min2, max2);
            xi = mathCos$1(endAngle) * rx + cx;
            yi = mathSin$1(endAngle) * ry + cy;
            break;

          case CMD.R:
            x0 = xi = data[i++];
            y0 = yi = data[i++];
            var width = data[i++];
            var height = data[i++];
            fromLine(x0, y0, x0 + width, y0 + height, min2, max2);
            break;

          case CMD.Z:
            xi = x0;
            yi = y0;
            break;
        }

        min(min$1, min$1, min2);
        max(max$1, max$1, max2);
      }

      if (i === 0) {
        min$1[0] = min$1[1] = max$1[0] = max$1[1] = 0;
      }

      return new BoundingRect(min$1[0], min$1[1], max$1[0] - min$1[0], max$1[1] - min$1[1]);
    };

    PathProxy.prototype._calculateLength = function () {
      var data = this.data;
      var len = this._len;
      var ux = this._ux;
      var uy = this._uy;
      var xi = 0;
      var yi = 0;
      var x0 = 0;
      var y0 = 0;

      if (!this._pathSegLen) {
        this._pathSegLen = [];
      }

      var pathSegLen = this._pathSegLen;
      var pathTotalLen = 0;
      var segCount = 0;

      for (var i = 0; i < len;) {
        var cmd = data[i++];

        if (i === 1) {
          xi = data[i];
          yi = data[i + 1];
          x0 = xi;
          y0 = yi;
        }

        var l = -1;

        switch (cmd) {
          case CMD.M:
            xi = x0 = data[i++];
            yi = y0 = data[i++];
            break;

          case CMD.L:
            {
              var x2 = data[i++];
              var y2 = data[i++];
              var dx = x2 - xi;
              var dy = y2 - yi;

              if (mathAbs(dx) > ux || mathAbs(dy) > uy || i === len - 1) {
                l = Math.sqrt(dx * dx + dy * dy);
                xi = x2;
                yi = y2;
              }

              break;
            }

          case CMD.C:
            {
              var x1 = data[i++];
              var y1 = data[i++];
              var x2 = data[i++];
              var y2 = data[i++];
              var x3 = data[i++];
              var y3 = data[i++];
              l = cubicLength(xi, yi, x1, y1, x2, y2, x3, y3, 10);
              xi = x3;
              yi = y3;
              break;
            }

          case CMD.Q:
            {
              var x1 = data[i++];
              var y1 = data[i++];
              var x2 = data[i++];
              var y2 = data[i++];
              l = quadraticLength(xi, yi, x1, y1, x2, y2, 10);
              xi = x2;
              yi = y2;
              break;
            }

          case CMD.A:
            var cx = data[i++];
            var cy = data[i++];
            var rx = data[i++];
            var ry = data[i++];
            var startAngle = data[i++];
            var delta = data[i++];
            var endAngle = delta + startAngle;
            i += 1;
            var anticlockwise = !data[i++];

            if (i === 1) {
              x0 = mathCos$1(startAngle) * rx + cx;
              y0 = mathSin$1(startAngle) * ry + cy;
            }

            l = mathMax$2(rx, ry) * mathMin$2(PI2$1, Math.abs(delta));
            xi = mathCos$1(endAngle) * rx + cx;
            yi = mathSin$1(endAngle) * ry + cy;
            break;

          case CMD.R:
            {
              x0 = xi = data[i++];
              y0 = yi = data[i++];
              var width = data[i++];
              var height = data[i++];
              l = width * 2 + height * 2;
              break;
            }

          case CMD.Z:
            {
              var dx = x0 - xi;
              var dy = y0 - yi;
              l = Math.sqrt(dx * dx + dy * dy);
              xi = x0;
              yi = y0;
              break;
            }
        }

        if (l >= 0) {
          pathSegLen[segCount++] = l;
          pathTotalLen += l;
        }
      }

      this._pathLen = pathTotalLen;
      return pathTotalLen;
    };

    PathProxy.prototype.rebuildPath = function (ctx, percent) {
      var d = this.data;
      var ux = this._ux;
      var uy = this._uy;
      var len = this._len;
      var x0;
      var y0;
      var xi;
      var yi;
      var x;
      var y;
      var drawPart = percent < 1;
      var pathSegLen;
      var pathTotalLen;
      var accumLength = 0;
      var segCount = 0;
      var displayedLength;

      if (drawPart) {
        if (!this._pathSegLen) {
          this._calculateLength();
        }

        pathSegLen = this._pathSegLen;
        pathTotalLen = this._pathLen;
        displayedLength = percent * pathTotalLen;

        if (!displayedLength) {
          return;
        }
      }

      lo: for (var i = 0; i < len;) {
        var cmd = d[i++];

        if (i === 1) {
          xi = d[i];
          yi = d[i + 1];
          x0 = xi;
          y0 = yi;
        }

        switch (cmd) {
          case CMD.M:
            x0 = xi = d[i++];
            y0 = yi = d[i++];
            ctx.moveTo(xi, yi);
            break;

          case CMD.L:
            {
              x = d[i++];
              y = d[i++];

              if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len - 1) {
                if (drawPart) {
                  var l = pathSegLen[segCount++];

                  if (accumLength + l > displayedLength) {
                    var t = (displayedLength - accumLength) / l;
                    ctx.lineTo(xi * (1 - t) + x * t, yi * (1 - t) + y * t);
                    break lo;
                  }

                  accumLength += l;
                }

                ctx.lineTo(x, y);
                xi = x;
                yi = y;
              }

              break;
            }

          case CMD.C:
            {
              var x1 = d[i++];
              var y1 = d[i++];
              var x2 = d[i++];
              var y2 = d[i++];
              var x3 = d[i++];
              var y3 = d[i++];

              if (drawPart) {
                var l = pathSegLen[segCount++];

                if (accumLength + l > displayedLength) {
                  var t = (displayedLength - accumLength) / l;
                  cubicSubdivide(xi, x1, x2, x3, t, tmpOutX);
                  cubicSubdivide(yi, y1, y2, y3, t, tmpOutY);
                  ctx.bezierCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2], tmpOutX[3], tmpOutY[3]);
                  break lo;
                }

                accumLength += l;
              }

              ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
              xi = x3;
              yi = y3;
              break;
            }

          case CMD.Q:
            {
              var x1 = d[i++];
              var y1 = d[i++];
              var x2 = d[i++];
              var y2 = d[i++];

              if (drawPart) {
                var l = pathSegLen[segCount++];

                if (accumLength + l > displayedLength) {
                  var t = (displayedLength - accumLength) / l;
                  quadraticSubdivide(xi, x1, x2, t, tmpOutX);
                  quadraticSubdivide(yi, y1, y2, t, tmpOutY);
                  ctx.quadraticCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2]);
                  break lo;
                }

                accumLength += l;
              }

              ctx.quadraticCurveTo(x1, y1, x2, y2);
              xi = x2;
              yi = y2;
              break;
            }

          case CMD.A:
            var cx = d[i++];
            var cy = d[i++];
            var rx = d[i++];
            var ry = d[i++];
            var startAngle = d[i++];
            var delta = d[i++];
            var psi = d[i++];
            var anticlockwise = !d[i++];
            var r = rx > ry ? rx : ry;
            var scaleX = rx > ry ? 1 : rx / ry;
            var scaleY = rx > ry ? ry / rx : 1;
            var isEllipse = mathAbs(rx - ry) > 1e-3;
            var endAngle = startAngle + delta;
            var breakBuild = false;

            if (drawPart) {
              var l = pathSegLen[segCount++];

              if (accumLength + l > displayedLength) {
                endAngle = startAngle + delta * (displayedLength - accumLength) / l;
                breakBuild = true;
              }

              accumLength += l;
            }

            if (isEllipse) {
              ctx.translate(cx, cy);
              ctx.rotate(psi);
              ctx.scale(scaleX, scaleY);
              ctx.arc(0, 0, r, startAngle, endAngle, anticlockwise);
              ctx.scale(1 / scaleX, 1 / scaleY);
              ctx.rotate(-psi);
              ctx.translate(-cx, -cy);
            } else {
              ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);
            }

            if (breakBuild) {
              break lo;
            }

            if (i === 1) {
              x0 = mathCos$1(startAngle) * rx + cx;
              y0 = mathSin$1(startAngle) * ry + cy;
            }

            xi = mathCos$1(endAngle) * rx + cx;
            yi = mathSin$1(endAngle) * ry + cy;
            break;

          case CMD.R:
            x0 = xi = d[i];
            y0 = yi = d[i + 1];
            x = d[i++];
            y = d[i++];
            var width = d[i++];
            var height = d[i++];

            if (drawPart) {
              var l = pathSegLen[segCount++];

              if (accumLength + l > displayedLength) {
                var d_1 = displayedLength - accumLength;
                ctx.moveTo(x, y);
                ctx.lineTo(x + mathMin$2(d_1, width), y);
                d_1 -= width;

                if (d_1 > 0) {
                  ctx.lineTo(x + width, y + mathMin$2(d_1, height));
                }

                d_1 -= height;

                if (d_1 > 0) {
                  ctx.lineTo(x + mathMax$2(width - d_1, 0), y + height);
                }

                d_1 -= width;

                if (d_1 > 0) {
                  ctx.lineTo(x, y + mathMax$2(height - d_1, 0));
                }

                break lo;
              }

              accumLength += l;
            }

            ctx.rect(x, y, width, height);
            break;

          case CMD.Z:
            if (drawPart) {
              var l = pathSegLen[segCount++];

              if (accumLength + l > displayedLength) {
                var t = (displayedLength - accumLength) / l;
                ctx.lineTo(xi * (1 - t) + x0 * t, yi * (1 - t) + y0 * t);
                break lo;
              }

              accumLength += l;
            }

            ctx.closePath();
            xi = x0;
            yi = y0;
        }
      }
    };

    PathProxy.CMD = CMD;

    PathProxy.initDefaultProps = function () {
      var proto = PathProxy.prototype;
      proto._saveData = true;
      proto._needsDash = false;
      proto._dashOffset = 0;
      proto._dashIdx = 0;
      proto._dashSum = 0;
      proto._ux = 0;
      proto._uy = 0;
    }();

    return PathProxy;
  }();

  function containStroke(x0, y0, x1, y1, lineWidth, x, y) {
    if (lineWidth === 0) {
      return false;
    }

    var _l = lineWidth;
    var _a = 0;
    var _b = x0;

    if (y > y0 + _l && y > y1 + _l || y < y0 - _l && y < y1 - _l || x > x0 + _l && x > x1 + _l || x < x0 - _l && x < x1 - _l) {
      return false;
    }

    if (x0 !== x1) {
      _a = (y0 - y1) / (x0 - x1);
      _b = (x0 * y1 - x1 * y0) / (x0 - x1);
    } else {
      return Math.abs(x - x0) <= _l / 2;
    }

    var tmp = _a * x - y + _b;

    var _s = tmp * tmp / (_a * _a + 1);

    return _s <= _l / 2 * _l / 2;
  }

  function containStroke$1(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {
    if (lineWidth === 0) {
      return false;
    }

    var _l = lineWidth;

    if (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l || y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l || x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l || x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l) {
      return false;
    }

    var d = cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, null);
    return d <= _l / 2;
  }

  function containStroke$2(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {
    if (lineWidth === 0) {
      return false;
    }

    var _l = lineWidth;

    if (y > y0 + _l && y > y1 + _l && y > y2 + _l || y < y0 - _l && y < y1 - _l && y < y2 - _l || x > x0 + _l && x > x1 + _l && x > x2 + _l || x < x0 - _l && x < x1 - _l && x < x2 - _l) {
      return false;
    }

    var d = quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, null);
    return d <= _l / 2;
  }

  var PI2$2 = Math.PI * 2;

  function normalizeRadian(angle) {
    angle %= PI2$2;

    if (angle < 0) {
      angle += PI2$2;
    }

    return angle;
  }

  var PI2$3 = Math.PI * 2;

  function containStroke$3(cx, cy, r, startAngle, endAngle, anticlockwise, lineWidth, x, y) {
    if (lineWidth === 0) {
      return false;
    }

    var _l = lineWidth;
    x -= cx;
    y -= cy;
    var d = Math.sqrt(x * x + y * y);

    if (d - _l > r || d + _l < r) {
      return false;
    }

    if (Math.abs(startAngle - endAngle) % PI2$3 < 1e-4) {
      return true;
    }

    if (anticlockwise) {
      var tmp = startAngle;
      startAngle = normalizeRadian(endAngle);
      endAngle = normalizeRadian(tmp);
    } else {
      startAngle = normalizeRadian(startAngle);
      endAngle = normalizeRadian(endAngle);
    }

    if (startAngle > endAngle) {
      endAngle += PI2$3;
    }

    var angle = Math.atan2(y, x);

    if (angle < 0) {
      angle += PI2$3;
    }

    return angle >= startAngle && angle <= endAngle || angle + PI2$3 >= startAngle && angle + PI2$3 <= endAngle;
  }

  function windingLine(x0, y0, x1, y1, x, y) {
    if (y > y0 && y > y1 || y < y0 && y < y1) {
      return 0;
    }

    if (y1 === y0) {
      return 0;
    }

    var t = (y - y0) / (y1 - y0);
    var dir = y1 < y0 ? 1 : -1;

    if (t === 1 || t === 0) {
      dir = y1 < y0 ? 0.5 : -0.5;
    }

    var x_ = t * (x1 - x0) + x0;
    return x_ === x ? Infinity : x_ > x ? dir : 0;
  }

  var CMD$1 = PathProxy.CMD;
  var PI2$4 = Math.PI * 2;
  var EPSILON$2 = 1e-4;

  function isAroundEqual(a, b) {
    return Math.abs(a - b) < EPSILON$2;
  }

  var roots = [-1, -1, -1];
  var extrema = [-1, -1];

  function swapExtrema() {
    var tmp = extrema[0];
    extrema[0] = extrema[1];
    extrema[1] = tmp;
  }

  function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {
    if (y > y0 && y > y1 && y > y2 && y > y3 || y < y0 && y < y1 && y < y2 && y < y3) {
      return 0;
    }

    var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots);

    if (nRoots === 0) {
      return 0;
    } else {
      var w = 0;
      var nExtrema = -1;
      var y0_ = void 0;
      var y1_ = void 0;

      for (var i = 0; i < nRoots; i++) {
        var t = roots[i];
        var unit = t === 0 || t === 1 ? 0.5 : 1;
        var x_ = cubicAt(x0, x1, x2, x3, t);

        if (x_ < x) {
          continue;
        }

        if (nExtrema < 0) {
          nExtrema = cubicExtrema(y0, y1, y2, y3, extrema);

          if (extrema[1] < extrema[0] && nExtrema > 1) {
            swapExtrema();
          }

          y0_ = cubicAt(y0, y1, y2, y3, extrema[0]);

          if (nExtrema > 1) {
            y1_ = cubicAt(y0, y1, y2, y3, extrema[1]);
          }
        }

        if (nExtrema === 2) {
          if (t < extrema[0]) {
            w += y0_ < y0 ? unit : -unit;
          } else if (t < extrema[1]) {
            w += y1_ < y0_ ? unit : -unit;
          } else {
            w += y3 < y1_ ? unit : -unit;
          }
        } else {
          if (t < extrema[0]) {
            w += y0_ < y0 ? unit : -unit;
          } else {
            w += y3 < y0_ ? unit : -unit;
          }
        }
      }

      return w;
    }
  }

  function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {
    if (y > y0 && y > y1 && y > y2 || y < y0 && y < y1 && y < y2) {
      return 0;
    }

    var nRoots = quadraticRootAt(y0, y1, y2, y, roots);

    if (nRoots === 0) {
      return 0;
    } else {
      var t = quadraticExtremum(y0, y1, y2);

      if (t >= 0 && t <= 1) {
        var w = 0;
        var y_ = quadraticAt(y0, y1, y2, t);

        for (var i = 0; i < nRoots; i++) {
          var unit = roots[i] === 0 || roots[i] === 1 ? 0.5 : 1;
          var x_ = quadraticAt(x0, x1, x2, roots[i]);

          if (x_ < x) {
            continue;
          }

          if (roots[i] < t) {
            w += y_ < y0 ? unit : -unit;
          } else {
            w += y2 < y_ ? unit : -unit;
          }
        }

        return w;
      } else {
        var unit = roots[0] === 0 || roots[0] === 1 ? 0.5 : 1;
        var x_ = quadraticAt(x0, x1, x2, roots[0]);

        if (x_ < x) {
          return 0;
        }

        return y2 < y0 ? unit : -unit;
      }
    }
  }

  function windingArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y) {
    y -= cy;

    if (y > r || y < -r) {
      return 0;
    }

    var tmp = Math.sqrt(r * r - y * y);
    roots[0] = -tmp;
    roots[1] = tmp;
    var dTheta = Math.abs(startAngle - endAngle);

    if (dTheta < 1e-4) {
      return 0;
    }

    if (dTheta % PI2$4 < 1e-4) {
      startAngle = 0;
      endAngle = PI2$4;
      var dir = anticlockwise ? 1 : -1;

      if (x >= roots[0] + cx && x <= roots[1] + cx) {
        return dir;
      } else {
        return 0;
      }
    }

    if (anticlockwise) {
      var tmp_1 = startAngle;
      startAngle = normalizeRadian(endAngle);
      endAngle = normalizeRadian(tmp_1);
    } else {
      startAngle = normalizeRadian(startAngle);
      endAngle = normalizeRadian(endAngle);
    }

    if (startAngle > endAngle) {
      endAngle += PI2$4;
    }

    var w = 0;

    for (var i = 0; i < 2; i++) {
      var x_ = roots[i];

      if (x_ + cx > x) {
        var angle = Math.atan2(y, x_);
        var dir = anticlockwise ? 1 : -1;

        if (angle < 0) {
          angle = PI2$4 + angle;
        }

        if (angle >= startAngle && angle <= endAngle || angle + PI2$4 >= startAngle && angle + PI2$4 <= endAngle) {
          if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {
            dir = -dir;
          }

          w += dir;
        }
      }
    }

    return w;
  }

  function containPath(data, lineWidth, isStroke, x, y) {
    var w = 0;
    var xi = 0;
    var yi = 0;
    var x0 = 0;
    var y0 = 0;
    var x1;
    var y1;

    for (var i = 0; i < data.length;) {
      var cmd = data[i++];

      if (cmd === CMD$1.M && i > 1) {
        if (!isStroke) {
          w += windingLine(xi, yi, x0, y0, x, y);
        }
      }

      if (i === 1) {
        xi = data[i];
        yi = data[i + 1];
        x0 = xi;
        y0 = yi;
      }

      switch (cmd) {
        case CMD$1.M:
          x0 = data[i++];
          y0 = data[i++];
          xi = x0;
          yi = y0;
          break;

        case CMD$1.L:
          if (isStroke) {
            if (containStroke(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {
              return true;
            }
          } else {
            w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;
          }

          xi = data[i++];
          yi = data[i++];
          break;

        case CMD$1.C:
          if (isStroke) {
            if (containStroke$1(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) {
              return true;
            }
          } else {
            w += windingCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y) || 0;
          }

          xi = data[i++];
          yi = data[i++];
          break;

        case CMD$1.Q:
          if (isStroke) {
            if (containStroke$2(xi, yi, data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) {
              return true;
            }
          } else {
            w += windingQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y) || 0;
          }

          xi = data[i++];
          yi = data[i++];
          break;

        case CMD$1.A:
          var cx = data[i++];
          var cy = data[i++];
          var rx = data[i++];
          var ry = data[i++];
          var theta = data[i++];
          var dTheta = data[i++];
          i += 1;
          var anticlockwise = !!(1 - data[i++]);
          x1 = Math.cos(theta) * rx + cx;
          y1 = Math.sin(theta) * ry + cy;

          if (i > 1) {
            w += windingLine(xi, yi, x1, y1, x, y);
          } else {
            x0 = x1;
            y0 = y1;
          }

          var _x = (x - cx) * ry / rx + cx;

          if (isStroke) {
            if (containStroke$3(cx, cy, ry, theta, theta + dTheta, anticlockwise, lineWidth, _x, y)) {
              return true;
            }
          } else {
            w += windingArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y);
          }

          xi = Math.cos(theta + dTheta) * rx + cx;
          yi = Math.sin(theta + dTheta) * ry + cy;
          break;

        case CMD$1.R:
          x0 = xi = data[i++];
          y0 = yi = data[i++];
          var width = data[i++];
          var height = data[i++];
          x1 = x0 + width;
          y1 = y0 + height;

          if (isStroke) {
            if (containStroke(x0, y0, x1, y0, lineWidth, x, y) || containStroke(x1, y0, x1, y1, lineWidth, x, y) || containStroke(x1, y1, x0, y1, lineWidth, x, y) || containStroke(x0, y1, x0, y0, lineWidth, x, y)) {
              return true;
            }
          } else {
            w += windingLine(x1, y0, x1, y1, x, y);
            w += windingLine(x0, y1, x0, y0, x, y);
          }

          break;

        case CMD$1.Z:
          if (isStroke) {
            if (containStroke(xi, yi, x0, y0, lineWidth, x, y)) {
              return true;
            }
          } else {
            w += windingLine(xi, yi, x0, y0, x, y);
          }

          xi = x0;
          yi = y0;
          break;
      }
    }

    if (!isStroke && !isAroundEqual(yi, y0)) {
      w += windingLine(xi, yi, x0, y0, x, y) || 0;
    }

    return w !== 0;
  }

  function contain(pathData, x, y) {
    return containPath(pathData, 0, false, x, y);
  }

  function containStroke$4(pathData, lineWidth, x, y) {
    return containPath(pathData, lineWidth, true, x, y);
  }

  var DEFAULT_PATH_STYLE = defaults({
    fill: '#000',
    stroke: null,
    strokePercent: 1,
    fillOpacity: 1,
    strokeOpacity: 1,
    lineDashOffset: 0,
    lineWidth: 1,
    lineCap: 'butt',
    miterLimit: 10,
    strokeNoScale: false,
    strokeFirst: false
  }, DEFAULT_COMMON_STYLE);
  var DEFAULT_PATH_ANIMATION_PROPS = {
    style: defaults({
      fill: true,
      stroke: true,
      strokePercent: true,
      fillOpacity: true,
      strokeOpacity: true,
      lineDashOffset: true,
      lineWidth: true,
      miterLimit: true
    }, DEFAULT_COMMON_ANIMATION_PROPS.style)
  };

  var Path = function (_super) {
    __extends(Path, _super);

    function Path(opts) {
      return _super.call(this, opts) || this;
    }

    Path.prototype._init = function (props) {
      var keysArr = keys(props);
      this.shape = this.getDefaultShape();
      var defaultStyle = this.getDefaultStyle();

      if (defaultStyle) {
        this.useStyle(defaultStyle);
      }

      for (var i = 0; i < keysArr.length; i++) {
        var key = keysArr[i];
        var value = props[key];

        if (key === 'style') {
          if (!this.style) {
            this.useStyle(value);
          } else {
            extend(this.style, value);
          }
        } else if (key === 'shape') {
          extend(this.shape, value);
        } else {
          _super.prototype.attrKV.call(this, key, value);
        }
      }

      if (!this.style) {
        this.useStyle({});
      }
    };

    Path.prototype.getDefaultStyle = function () {
      return null;
    };

    Path.prototype.getDefaultShape = function () {
      return {};
    };

    Path.prototype.canBeInsideText = function () {
      return this.hasFill();
    };

    Path.prototype.getInsideTextFill = function () {
      var pathFill = this.style.fill;

      if (pathFill !== 'none') {
        if (isString(pathFill)) {
          var fillLum = lum(pathFill, 0);

          if (fillLum > 0.6) {
            return DARK_LABEL_COLOR;
          } else if (fillLum > 0.2) {
            return LIGHTER_LABEL_COLOR;
          }

          return LIGHT_LABEL_COLOR;
        } else if (pathFill) {
          return LIGHT_LABEL_COLOR;
        }
      }

      return DARK_LABEL_COLOR;
    };

    Path.prototype.getInsideTextStroke = function (textFill) {
      var pathFill = this.style.fill;

      if (isString(pathFill)) {
        var zr = this.__zr;
        var isDarkMode = !!(zr && zr.isDarkMode());
        var isDarkLabel = lum(textFill, 0) < DARK_MODE_THRESHOLD;

        if (isDarkMode === isDarkLabel) {
          return pathFill;
        }
      }
    };

    Path.prototype.buildPath = function (ctx, shapeCfg, inBundle) {};

    Path.prototype.pathUpdated = function () {
      this.__dirty &= ~Path.SHAPE_CHANGED_BIT;
    };

    Path.prototype.createPathProxy = function () {
      this.path = new PathProxy(false);
    };

    Path.prototype.hasStroke = function () {
      var style = this.style;
      var stroke = style.stroke;
      return !(stroke == null || stroke === 'none' || !(style.lineWidth > 0));
    };

    Path.prototype.hasFill = function () {
      var style = this.style;
      var fill = style.fill;
      return fill != null && fill !== 'none';
    };

    Path.prototype.getBoundingRect = function () {
      var rect = this._rect;
      var style = this.style;
      var needsUpdateRect = !rect;

      if (needsUpdateRect) {
        var firstInvoke = false;

        if (!this.path) {
          firstInvoke = true;
          this.createPathProxy();
        }

        var path = this.path;

        if (firstInvoke || this.__dirty & Path.SHAPE_CHANGED_BIT) {
          path.beginPath();
          this.buildPath(path, this.shape, false);
          this.pathUpdated();
        }

        rect = path.getBoundingRect();
      }

      this._rect = rect;

      if (this.hasStroke()) {
        var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());

        if (this.__dirty || needsUpdateRect) {
          rectWithStroke.copy(rect);
          var lineScale = style.strokeNoScale ? this.getLineScale() : 1;
          var w = style.lineWidth;

          if (!this.hasFill()) {
            w = Math.max(w, this.strokeContainThreshold || 4);
          }

          if (lineScale > 1e-10) {
            rectWithStroke.width += w / lineScale;
            rectWithStroke.height += w / lineScale;
            rectWithStroke.x -= w / lineScale / 2;
            rectWithStroke.y -= w / lineScale / 2;
          }
        }

        return rectWithStroke;
      }

      return rect;
    };

    Path.prototype.contain = function (x, y) {
      var localPos = this.transformCoordToLocal(x, y);
      var rect = this.getBoundingRect();
      var style = this.style;
      x = localPos[0];
      y = localPos[1];

      if (rect.contain(x, y)) {
        var pathData = this.path.data;

        if (this.hasStroke()) {
          var lineWidth = style.lineWidth;
          var lineScale = style.strokeNoScale ? this.getLineScale() : 1;

          if (lineScale > 1e-10) {
            if (!this.hasFill()) {
              lineWidth = Math.max(lineWidth, this.strokeContainThreshold);
            }

            if (containStroke$4(pathData, lineWidth / lineScale, x, y)) {
              return true;
            }
          }
        }

        if (this.hasFill()) {
          return contain(pathData, x, y);
        }
      }

      return false;
    };

    Path.prototype.dirtyShape = function () {
      this.__dirty |= Path.SHAPE_CHANGED_BIT;

      if (this._rect) {
        this._rect = null;
      }

      this.markRedraw();
    };

    Path.prototype.dirty = function () {
      this.dirtyStyle();
      this.dirtyShape();
    };

    Path.prototype.animateShape = function (loop) {
      return this.animate('shape', loop);
    };

    Path.prototype.updateDuringAnimation = function (targetKey) {
      if (targetKey === 'style') {
        this.dirtyStyle();
      } else if (targetKey === 'shape') {
        this.dirtyShape();
      } else {
        this.markRedraw();
      }
    };

    Path.prototype.attrKV = function (key, value) {
      if (key === 'shape') {
        this.setShape(value);
      } else {
        _super.prototype.attrKV.call(this, key, value);
      }
    };

    Path.prototype.setShape = function (keyOrObj, value) {
      var shape = this.shape;

      if (!shape) {
        shape = this.shape = {};
      }

      if (typeof keyOrObj === 'string') {
        shape[keyOrObj] = value;
      } else {
        extend(shape, keyOrObj);
      }

      this.dirtyShape();
      return this;
    };

    Path.prototype.shapeChanged = function () {
      return !!(this.__dirty & Path.SHAPE_CHANGED_BIT);
    };

    Path.prototype.createStyle = function (obj) {
      return createObject(DEFAULT_PATH_STYLE, obj);
    };

    Path.prototype._innerSaveToNormal = function (toState) {
      _super.prototype._innerSaveToNormal.call(this, toState);

      var normalState = this._normalState;

      if (toState.shape && !normalState.shape) {
        normalState.shape = extend({}, this.shape);
      }
    };

    Path.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
      _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg);

      var needsRestoreToNormal = !(state && keepCurrentStates);
      var targetShape;

      if (state && state.shape) {
        if (transition) {
          if (keepCurrentStates) {
            targetShape = state.shape;
          } else {
            targetShape = extend({}, normalState.shape);
            extend(targetShape, state.shape);
          }
        } else {
          targetShape = extend({}, keepCurrentStates ? this.shape : normalState.shape);
          extend(targetShape, state.shape);
        }
      } else if (needsRestoreToNormal) {
        targetShape = normalState.shape;
      }

      if (targetShape) {
        if (transition) {
          this.shape = extend({}, this.shape);
          var targetShapePrimaryProps = {};
          var shapeKeys = keys(targetShape);

          for (var i = 0; i < shapeKeys.length; i++) {
            var key = shapeKeys[i];

            if (typeof targetShape[key] === 'object') {
              this.shape[key] = targetShape[key];
            } else {
              targetShapePrimaryProps[key] = targetShape[key];
            }
          }

          this._transitionState(stateName, {
            shape: targetShapePrimaryProps
          }, animationCfg);
        } else {
          this.shape = targetShape;
          this.dirtyShape();
        }
      }
    };

    Path.prototype._mergeStates = function (states) {
      var mergedState = _super.prototype._mergeStates.call(this, states);

      var mergedShape;

      for (var i = 0; i < states.length; i++) {
        var state = states[i];

        if (state.shape) {
          mergedShape = mergedShape || {};

          this._mergeStyle(mergedShape, state.shape);
        }
      }

      if (mergedShape) {
        mergedState.shape = mergedShape;
      }

      return mergedState;
    };

    Path.prototype._getAnimationStyleProps = function () {
      return DEFAULT_PATH_ANIMATION_PROPS;
    };

    Path.prototype.isZeroArea = function () {
      return false;
    };

    Path.extend = function (defaultProps) {
      var Sub = function (_super) {
        __extends(Sub, _super);

        function Sub(opts) {
          var _this = _super.call(this, opts) || this;

          defaultProps.init && defaultProps.init.call(_this, opts);
          return _this;
        }

        Sub.prototype.getDefaultStyle = function () {
          return clone(defaultProps.style);
        };

        Sub.prototype.getDefaultShape = function () {
          return clone(defaultProps.shape);
        };

        return Sub;
      }(Path);

      for (var key in defaultProps) {
        if (typeof defaultProps[key] === 'function') {
          Sub.prototype[key] = defaultProps[key];
        }
      }

      return Sub;
    };

    Path.SHAPE_CHANGED_BIT = 4;

    Path.initDefaultProps = function () {
      var pathProto = Path.prototype;
      pathProto.type = 'path';
      pathProto.strokeContainThreshold = 5;
      pathProto.segmentIgnoreThreshold = 0;
      pathProto.subPixelOptimize = false;
      pathProto.autoBatch = false;
      pathProto.__dirty = Element.REDARAW_BIT | Displayable.STYLE_CHANGED_BIT | Path.SHAPE_CHANGED_BIT;
    }();

    return Path;
  }(Displayable);

  var CMD$2 = PathProxy.CMD;
  var points = [[], [], []];
  var mathSqrt$2 = Math.sqrt;
  var mathAtan2 = Math.atan2;

  function transformPath(path, m) {
    var data = path.data;
    var cmd;
    var nPoint;
    var i;
    var j;
    var k;
    var p;
    var M = CMD$2.M;
    var C = CMD$2.C;
    var L = CMD$2.L;
    var R = CMD$2.R;
    var A = CMD$2.A;
    var Q = CMD$2.Q;

    for (i = 0, j = 0; i < data.length;) {
      cmd = data[i++];
      j = i;
      nPoint = 0;

      switch (cmd) {
        case M:
          nPoint = 1;
          break;

        case L:
          nPoint = 1;
          break;

        case C:
          nPoint = 3;
          break;

        case Q:
          nPoint = 2;
          break;

        case A:
          var x = m[4];
          var y = m[5];
          var sx = mathSqrt$2(m[0] * m[0] + m[1] * m[1]);
          var sy = mathSqrt$2(m[2] * m[2] + m[3] * m[3]);
          var angle = mathAtan2(-m[1] / sy, m[0] / sx);
          data[i] *= sx;
          data[i++] += x;
          data[i] *= sy;
          data[i++] += y;
          data[i++] *= sx;
          data[i++] *= sy;
          data[i++] += angle;
          data[i++] += angle;
          i += 2;
          j = i;
          break;

        case R:
          p[0] = data[i++];
          p[1] = data[i++];
          applyTransform(p, p, m);
          data[j++] = p[0];
          data[j++] = p[1];
          p[0] += data[i++];
          p[1] += data[i++];
          applyTransform(p, p, m);
          data[j++] = p[0];
          data[j++] = p[1];
      }

      for (k = 0; k < nPoint; k++) {
        var p_1 = points[k];
        p_1[0] = data[i++];
        p_1[1] = data[i++];
        applyTransform(p_1, p_1, m);
        data[j++] = p_1[0];
        data[j++] = p_1[1];
      }
    }
  }

  var mathSqrt$3 = Math.sqrt;
  var mathSin$2 = Math.sin;
  var mathCos$2 = Math.cos;
  var PI$1 = Math.PI;

  function vMag(v) {
    return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
  }

  function vRatio(u, v) {
    return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
  }

  function vAngle(u, v) {
    return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v));
  }

  function processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {
    var psi = psiDeg * (PI$1 / 180.0);
    var xp = mathCos$2(psi) * (x1 - x2) / 2.0 + mathSin$2(psi) * (y1 - y2) / 2.0;
    var yp = -1 * mathSin$2(psi) * (x1 - x2) / 2.0 + mathCos$2(psi) * (y1 - y2) / 2.0;
    var lambda = xp * xp / (rx * rx) + yp * yp / (ry * ry);

    if (lambda > 1) {
      rx *= mathSqrt$3(lambda);
      ry *= mathSqrt$3(lambda);
    }

    var f = (fa === fs ? -1 : 1) * mathSqrt$3((rx * rx * (ry * ry) - rx * rx * (yp * yp) - ry * ry * (xp * xp)) / (rx * rx * (yp * yp) + ry * ry * (xp * xp))) || 0;
    var cxp = f * rx * yp / ry;
    var cyp = f * -ry * xp / rx;
    var cx = (x1 + x2) / 2.0 + mathCos$2(psi) * cxp - mathSin$2(psi) * cyp;
    var cy = (y1 + y2) / 2.0 + mathSin$2(psi) * cxp + mathCos$2(psi) * cyp;
    var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]);
    var u = [(xp - cxp) / rx, (yp - cyp) / ry];
    var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry];
    var dTheta = vAngle(u, v);

    if (vRatio(u, v) <= -1) {
      dTheta = PI$1;
    }

    if (vRatio(u, v) >= 1) {
      dTheta = 0;
    }

    if (dTheta < 0) {
      var n = Math.round(dTheta / PI$1 * 1e6) / 1e6;
      dTheta = PI$1 * 2 + n % 2 * PI$1;
    }

    path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);
  }

  var commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig;
  var numberReg = /-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g;

  function createPathProxyFromString(data) {
    if (!data) {
      return new PathProxy();
    }

    var cpx = 0;
    var cpy = 0;
    var subpathX = cpx;
    var subpathY = cpy;
    var prevCmd;
    var path = new PathProxy();
    var CMD = PathProxy.CMD;
    var cmdList = data.match(commandReg);

    for (var l = 0; l < cmdList.length; l++) {
      var cmdText = cmdList[l];
      var cmdStr = cmdText.charAt(0);
      var cmd = void 0;
      var p = cmdText.match(numberReg) || [];
      var pLen = p.length;

      for (var i = 0; i < pLen; i++) {
        p[i] = parseFloat(p[i]);
      }

      var off = 0;

      while (off < pLen) {
        var ctlPtx = void 0;
        var ctlPty = void 0;
        var rx = void 0;
        var ry = void 0;
        var psi = void 0;
        var fa = void 0;
        var fs = void 0;
        var x1 = cpx;
        var y1 = cpy;
        var len = void 0;
        var pathData = void 0;

        switch (cmdStr) {
          case 'l':
            cpx += p[off++];
            cpy += p[off++];
            cmd = CMD.L;
            path.addData(cmd, cpx, cpy);
            break;

          case 'L':
            cpx = p[off++];
            cpy = p[off++];
            cmd = CMD.L;
            path.addData(cmd, cpx, cpy);
            break;

          case 'm':
            cpx += p[off++];
            cpy += p[off++];
            cmd = CMD.M;
            path.addData(cmd, cpx, cpy);
            subpathX = cpx;
            subpathY = cpy;
            cmdStr = 'l';
            break;

          case 'M':
            cpx = p[off++];
            cpy = p[off++];
            cmd = CMD.M;
            path.addData(cmd, cpx, cpy);
            subpathX = cpx;
            subpathY = cpy;
            cmdStr = 'L';
            break;

          case 'h':
            cpx += p[off++];
            cmd = CMD.L;
            path.addData(cmd, cpx, cpy);
            break;

          case 'H':
            cpx = p[off++];
            cmd = CMD.L;
            path.addData(cmd, cpx, cpy);
            break;

          case 'v':
            cpy += p[off++];
            cmd = CMD.L;
            path.addData(cmd, cpx, cpy);
            break;

          case 'V':
            cpy = p[off++];
            cmd = CMD.L;
            path.addData(cmd, cpx, cpy);
            break;

          case 'C':
            cmd = CMD.C;
            path.addData(cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]);
            cpx = p[off - 2];
            cpy = p[off - 1];
            break;

          case 'c':
            cmd = CMD.C;
            path.addData(cmd, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy);
            cpx += p[off - 2];
            cpy += p[off - 1];
            break;

          case 'S':
            ctlPtx = cpx;
            ctlPty = cpy;
            len = path.len();
            pathData = path.data;

            if (prevCmd === CMD.C) {
              ctlPtx += cpx - pathData[len - 4];
              ctlPty += cpy - pathData[len - 3];
            }

            cmd = CMD.C;
            x1 = p[off++];
            y1 = p[off++];
            cpx = p[off++];
            cpy = p[off++];
            path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
            break;

          case 's':
            ctlPtx = cpx;
            ctlPty = cpy;
            len = path.len();
            pathData = path.data;

            if (prevCmd === CMD.C) {
              ctlPtx += cpx - pathData[len - 4];
              ctlPty += cpy - pathData[len - 3];
            }

            cmd = CMD.C;
            x1 = cpx + p[off++];
            y1 = cpy + p[off++];
            cpx += p[off++];
            cpy += p[off++];
            path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
            break;

          case 'Q':
            x1 = p[off++];
            y1 = p[off++];
            cpx = p[off++];
            cpy = p[off++];
            cmd = CMD.Q;
            path.addData(cmd, x1, y1, cpx, cpy);
            break;

          case 'q':
            x1 = p[off++] + cpx;
            y1 = p[off++] + cpy;
            cpx += p[off++];
            cpy += p[off++];
            cmd = CMD.Q;
            path.addData(cmd, x1, y1, cpx, cpy);
            break;

          case 'T':
            ctlPtx = cpx;
            ctlPty = cpy;
            len = path.len();
            pathData = path.data;

            if (prevCmd === CMD.Q) {
              ctlPtx += cpx - pathData[len - 4];
              ctlPty += cpy - pathData[len - 3];
            }

            cpx = p[off++];
            cpy = p[off++];
            cmd = CMD.Q;
            path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
            break;

          case 't':
            ctlPtx = cpx;
            ctlPty = cpy;
            len = path.len();
            pathData = path.data;

            if (prevCmd === CMD.Q) {
              ctlPtx += cpx - pathData[len - 4];
              ctlPty += cpy - pathData[len - 3];
            }

            cpx += p[off++];
            cpy += p[off++];
            cmd = CMD.Q;
            path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
            break;

          case 'A':
            rx = p[off++];
            ry = p[off++];
            psi = p[off++];
            fa = p[off++];
            fs = p[off++];
            x1 = cpx, y1 = cpy;
            cpx = p[off++];
            cpy = p[off++];
            cmd = CMD.A;
            processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path);
            break;

          case 'a':
            rx = p[off++];
            ry = p[off++];
            psi = p[off++];
            fa = p[off++];
            fs = p[off++];
            x1 = cpx, y1 = cpy;
            cpx += p[off++];
            cpy += p[off++];
            cmd = CMD.A;
            processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path);
            break;
        }
      }

      if (cmdStr === 'z' || cmdStr === 'Z') {
        cmd = CMD.Z;
        path.addData(cmd);
        cpx = subpathX;
        cpy = subpathY;
      }

      prevCmd = cmd;
    }

    path.toStatic();
    return path;
  }

  var SVGPath = function (_super) {
    __extends(SVGPath, _super);

    function SVGPath() {
      return _super !== null && _super.apply(this, arguments) || this;
    }

    SVGPath.prototype.applyTransform = function (m) {};

    return SVGPath;
  }(Path);

  function isPathProxy(path) {
    return path.setData != null;
  }

  function createPathOptions(str, opts) {
    var pathProxy = createPathProxyFromString(str);
    var innerOpts = extend({}, opts);

    innerOpts.buildPath = function (path) {
      if (isPathProxy(path)) {
        path.setData(pathProxy.data);
        var ctx = path.getContext();

        if (ctx) {
          path.rebuildPath(ctx, 1);
        }
      } else {
        var ctx = path;
        pathProxy.rebuildPath(ctx, 1);
      }
    };

    innerOpts.applyTransform = function (m) {
      transformPath(pathProxy, m);
      this.dirtyShape();
    };

    return innerOpts;
  }

  function createFromString(str, opts) {
    return new SVGPath(createPathOptions(str, opts));
  }

  var Group = function (_super) {
    __extends(Group, _super);

    function Group(opts) {
      var _this = _super.call(this) || this;

      _this.isGroup = true;
      _this._children = [];

      _this.attr(opts);

      return _this;
    }

    Group.prototype.childrenRef = function () {
      return this._children;
    };

    Group.prototype.children = function () {
      return this._children.slice();
    };

    Group.prototype.childAt = function (idx) {
      return this._children[idx];
    };

    Group.prototype.childOfName = function (name) {
      var children = this._children;

      for (var i = 0; i < children.length; i++) {
        if (children[i].name === name) {
          return children[i];
        }
      }
    };

    Group.prototype.childCount = function () {
      return this._children.length;
    };

    Group.prototype.add = function (child) {
      if (child) {
        if (child !== this && child.parent !== this) {
          this._children.push(child);

          this._doAdd(child);
        }

        if (child.__hostTarget) {
          throw 'This elemenet has been used as an attachment';
        }
      }

      return this;
    };

    Group.prototype.addBefore = function (child, nextSibling) {
      if (child && child !== this && child.parent !== this && nextSibling && nextSibling.parent === this) {
        var children = this._children;
        var idx = children.indexOf(nextSibling);

        if (idx >= 0) {
          children.splice(idx, 0, child);

          this._doAdd(child);
        }
      }

      return this;
    };

    Group.prototype.replaceAt = function (child, index) {
      var children = this._children;
      var old = children[index];

      if (child && child !== this && child.parent !== this && child !== old) {
        children[index] = child;
        old.parent = null;
        var zr = this.__zr;

        if (zr) {
          old.removeSelfFromZr(zr);
        }

        this._doAdd(child);
      }

      return this;
    };

    Group.prototype._doAdd = function (child) {
      if (child.parent) {
        child.parent.remove(child);
      }

      child.parent = this;
      var zr = this.__zr;

      if (zr && zr !== child.__zr) {
        child.addSelfToZr(zr);
      }

      zr && zr.refresh();
    };

    Group.prototype.remove = function (child) {
      var zr = this.__zr;
      var children = this._children;
      var idx = indexOf(children, child);

      if (idx < 0) {
        return this;
      }

      children.splice(idx, 1);
      child.parent = null;

      if (zr) {
        child.removeSelfFromZr(zr);
      }

      zr && zr.refresh();
      return this;
    };

    Group.prototype.removeAll = function () {
      var children = this._children;
      var zr = this.__zr;

      for (var i = 0; i < children.length; i++) {
        var child = children[i];

        if (zr) {
          child.removeSelfFromZr(zr);
        }

        child.parent = null;
      }

      children.length = 0;
      return this;
    };

    Group.prototype.eachChild = function (cb, context) {
      var children = this._children;

      for (var i = 0; i < children.length; i++) {
        var child = children[i];
        cb.call(context, child, i);
      }

      return this;
    };

    Group.prototype.traverse = function (cb, context) {
      for (var i = 0; i < this._children.length; i++) {
        var child = this._children[i];
        var stopped = cb.call(context, child);

        if (child.isGroup && !stopped) {
          child.traverse(cb, context);
        }
      }

      return this;
    };

    Group.prototype.addSelfToZr = function (zr) {
      _super.prototype.addSelfToZr.call(this, zr);

      for (var i = 0; i < this._children.length; i++) {
        var child = this._children[i];
        child.addSelfToZr(zr);
      }
    };

    Group.prototype.removeSelfFromZr = function (zr) {
      _super.prototype.removeSelfFromZr.call(this, zr);

      for (var i = 0; i < this._children.length; i++) {
        var child = this._children[i];
        child.removeSelfFromZr(zr);
      }
    };

    Group.prototype.getBoundingRect = function (includeChildren) {
      var tmpRect = new BoundingRect(0, 0, 0, 0);
      var children = includeChildren || this._children;
      var tmpMat = [];
      var rect = null;

      for (var i = 0; i < children.length; i++) {
        var child = children[i];

        if (child.ignore || child.invisible) {
          continue;
        }

        var childRect = child.getBoundingRect();
        var transform = child.getLocalTransform(tmpMat);

        if (transform) {
          BoundingRect.applyTransform(tmpRect, childRect, transform);
          rect = rect || tmpRect.clone();
          rect.union(tmpRect);
        } else {
          rect = rect || childRect.clone();
          rect.union(childRect);
        }
      }

      return rect || tmpRect;
    };

    return Group;
  }(Element);

  Group.prototype.type = 'group';
  var DEFAULT_IMAGE_STYLE = defaults({
    x: 0,
    y: 0
  }, DEFAULT_COMMON_STYLE);
  var DEFAULT_IMAGE_ANIMATION_PROPS = {
    style: defaults({
      x: true,
      y: true,
      width: true,
      height: true,
      sx: true,
      sy: true,
      sWidth: true,
      sHeight: true
    }, DEFAULT_COMMON_ANIMATION_PROPS.style)
  };

  var ZRImage = function (_super) {
    __extends(ZRImage, _super);

    function ZRImage() {
      return _super !== null && _super.apply(this, arguments) || this;
    }

    ZRImage.prototype.createStyle = function (obj) {
      return createObject(DEFAULT_IMAGE_STYLE, obj);
    };

    ZRImage.prototype._getAnimationStyleProps = function () {
      return DEFAULT_IMAGE_ANIMATION_PROPS;
    };

    ZRImage.prototype.getBoundingRect = function () {
      var style = this.style;

      if (!this._rect) {
        this._rect = new BoundingRect(style.x || 0, style.y || 0, style.width || 0, style.height || 0);
      }

      return this._rect;
    };

    return ZRImage;
  }(Displayable);

  ZRImage.prototype.type = 'image';

  var CircleShape = function () {
    function CircleShape() {
      this.cx = 0;
      this.cy = 0;
      this.r = 0;
    }

    return CircleShape;
  }();

  var Circle = function (_super) {
    __extends(Circle, _super);

    function Circle(opts) {
      return _super.call(this, opts) || this;
    }

    Circle.prototype.getDefaultShape = function () {
      return new CircleShape();
    };

    Circle.prototype.buildPath = function (ctx, shape, inBundle) {
      if (inBundle) {
        ctx.moveTo(shape.cx + shape.r, shape.cy);
      }

      ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2);
    };

    return Circle;
  }(Path);

  Circle.prototype.type = 'circle';

  function buildPath(ctx, shape) {
    var x = shape.x;
    var y = shape.y;
    var width = shape.width;
    var height = shape.height;
    var r = shape.r;
    var r1;
    var r2;
    var r3;
    var r4;

    if (width < 0) {
      x = x + width;
      width = -width;
    }

    if (height < 0) {
      y = y + height;
      height = -height;
    }

    if (typeof r === 'number') {
      r1 = r2 = r3 = r4 = r;
    } else if (r instanceof Array) {
      if (r.length === 1) {
        r1 = r2 = r3 = r4 = r[0];
      } else if (r.length === 2) {
        r1 = r3 = r[0];
        r2 = r4 = r[1];
      } else if (r.length === 3) {
        r1 = r[0];
        r2 = r4 = r[1];
        r3 = r[2];
      } else {
        r1 = r[0];
        r2 = r[1];
        r3 = r[2];
        r4 = r[3];
      }
    } else {
      r1 = r2 = r3 = r4 = 0;
    }

    var total;

    if (r1 + r2 > width) {
      total = r1 + r2;
      r1 *= width / total;
      r2 *= width / total;
    }

    if (r3 + r4 > width) {
      total = r3 + r4;
      r3 *= width / total;
      r4 *= width / total;
    }

    if (r2 + r3 > height) {
      total = r2 + r3;
      r2 *= height / total;
      r3 *= height / total;
    }

    if (r1 + r4 > height) {
      total = r1 + r4;
      r1 *= height / total;
      r4 *= height / total;
    }

    ctx.moveTo(x + r1, y);
    ctx.lineTo(x + width - r2, y);
    r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0);
    ctx.lineTo(x + width, y + height - r3);
    r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2);
    ctx.lineTo(x + r4, y + height);
    r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI);
    ctx.lineTo(x, y + r1);
    r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5);
  }

  var round = Math.round;

  function subPixelOptimizeLine(outputShape, inputShape, style) {
    if (!inputShape) {
      return;
    }

    var x1 = inputShape.x1;
    var x2 = inputShape.x2;
    var y1 = inputShape.y1;
    var y2 = inputShape.y2;
    outputShape.x1 = x1;
    outputShape.x2 = x2;
    outputShape.y1 = y1;
    outputShape.y2 = y2;
    var lineWidth = style && style.lineWidth;

    if (!lineWidth) {
      return outputShape;
    }

    if (round(x1 * 2) === round(x2 * 2)) {
      outputShape.x1 = outputShape.x2 = subPixelOptimize(x1, lineWidth, true);
    }

    if (round(y1 * 2) === round(y2 * 2)) {
      outputShape.y1 = outputShape.y2 = subPixelOptimize(y1, lineWidth, true);
    }

    return outputShape;
  }

  function subPixelOptimizeRect(outputShape, inputShape, style) {
    if (!inputShape) {
      return;
    }

    var originX = inputShape.x;
    var originY = inputShape.y;
    var originWidth = inputShape.width;
    var originHeight = inputShape.height;
    outputShape.x = originX;
    outputShape.y = originY;
    outputShape.width = originWidth;
    outputShape.height = originHeight;
    var lineWidth = style && style.lineWidth;

    if (!lineWidth) {
      return outputShape;
    }

    outputShape.x = subPixelOptimize(originX, lineWidth, true);
    outputShape.y = subPixelOptimize(originY, lineWidth, true);
    outputShape.width = Math.max(subPixelOptimize(originX + originWidth, lineWidth, false) - outputShape.x, originWidth === 0 ? 0 : 1);
    outputShape.height = Math.max(subPixelOptimize(originY + originHeight, lineWidth, false) - outputShape.y, originHeight === 0 ? 0 : 1);
    return outputShape;
  }

  function subPixelOptimize(position, lineWidth, positiveOrNegative) {
    if (!lineWidth) {
      return position;
    }

    var doubledPosition = round(position * 2);
    return (doubledPosition + round(lineWidth)) % 2 === 0 ? doubledPosition / 2 : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;
  }

  var RectShape = function () {
    function RectShape() {
      this.x = 0;
      this.y = 0;
      this.width = 0;
      this.height = 0;
    }

    return RectShape;
  }();

  var subPixelOptimizeOutputShape = {};

  var Rect = function (_super) {
    __extends(Rect, _super);

    function Rect(opts) {
      return _super.call(this, opts) || this;
    }

    Rect.prototype.getDefaultShape = function () {
      return new RectShape();
    };

    Rect.prototype.buildPath = function (ctx, shape) {
      var x;
      var y;
      var width;
      var height;

      if (this.subPixelOptimize) {
        var optimizedShape = subPixelOptimizeRect(subPixelOptimizeOutputShape, shape, this.style);
        x = optimizedShape.x;
        y = optimizedShape.y;
        width = optimizedShape.width;
        height = optimizedShape.height;
        optimizedShape.r = shape.r;
        shape = optimizedShape;
      } else {
        x = shape.x;
        y = shape.y;
        width = shape.width;
        height = shape.height;
      }

      if (!shape.r) {
        ctx.rect(x, y, width, height);
      } else {
        buildPath(ctx, shape);
      }
    };

    Rect.prototype.isZeroArea = function () {
      return !this.shape.width || !this.shape.height;
    };

    return Rect;
  }(Path);

  Rect.prototype.type = 'rect';

  var EllipseShape = function () {
    function EllipseShape() {
      this.cx = 0;
      this.cy = 0;
      this.rx = 0;
      this.ry = 0;
    }

    return EllipseShape;
  }();

  var Ellipse = function (_super) {
    __extends(Ellipse, _super);

    function Ellipse(opts) {
      return _super.call(this, opts) || this;
    }

    Ellipse.prototype.getDefaultShape = function () {
      return new EllipseShape();
    };

    Ellipse.prototype.buildPath = function (ctx, shape) {
      var k = 0.5522848;
      var x = shape.cx;
      var y = shape.cy;
      var a = shape.rx;
      var b = shape.ry;
      var ox = a * k;
      var oy = b * k;
      ctx.moveTo(x - a, y);
      ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);
      ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);
      ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b);
      ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);
      ctx.closePath();
    };

    return Ellipse;
  }(Path);

  Ellipse.prototype.type = 'ellipse';
  var subPixelOptimizeOutputShape$1 = {};

  var LineShape = function () {
    function LineShape() {
      this.x1 = 0;
      this.y1 = 0;
      this.x2 = 0;
      this.y2 = 0;
      this.percent = 1;
    }

    return LineShape;
  }();

  var Line = function (_super) {
    __extends(Line, _super);

    function Line(opts) {
      return _super.call(this, opts) || this;
    }

    Line.prototype.getDefaultStyle = function () {
      return {
        stroke: '#000',
        fill: null
      };
    };

    Line.prototype.getDefaultShape = function () {
      return new LineShape();
    };

    Line.prototype.buildPath = function (ctx, shape) {
      var x1;
      var y1;
      var x2;
      var y2;

      if (this.subPixelOptimize) {
        var optimizedShape = subPixelOptimizeLine(subPixelOptimizeOutputShape$1, shape, this.style);
        x1 = optimizedShape.x1;
        y1 = optimizedShape.y1;
        x2 = optimizedShape.x2;
        y2 = optimizedShape.y2;
      } else {
        x1 = shape.x1;
        y1 = shape.y1;
        x2 = shape.x2;
        y2 = shape.y2;
      }

      var percent = shape.percent;

      if (percent === 0) {
        return;
      }

      ctx.moveTo(x1, y1);

      if (percent < 1) {
        x2 = x1 * (1 - percent) + x2 * percent;
        y2 = y1 * (1 - percent) + y2 * percent;
      }

      ctx.lineTo(x2, y2);
    };

    Line.prototype.pointAt = function (p) {
      var shape = this.shape;
      return [shape.x1 * (1 - p) + shape.x2 * p, shape.y1 * (1 - p) + shape.y2 * p];
    };

    return Line;
  }(Path);

  Line.prototype.type = 'line';

  function interpolate(p0, p1, p2, p3, t, t2, t3) {
    var v0 = (p2 - p0) * 0.5;
    var v1 = (p3 - p1) * 0.5;
    return (2 * (p1 - p2) + v0 + v1) * t3 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2 + v0 * t + p1;
  }

  function smoothSpline(points, isLoop) {
    var len = points.length;
    var ret = [];
    var distance$1 = 0;

    for (var i = 1; i < len; i++) {
      distance$1 += distance(points[i - 1], points[i]);
    }

    var segs = distance$1 / 2;
    segs = segs < len ? len : segs;

    for (var i = 0; i < segs; i++) {
      var pos = i / (segs - 1) * (isLoop ? len : len - 1);
      var idx = Math.floor(pos);
      var w = pos - idx;
      var p0 = void 0;
      var p1 = points[idx % len];
      var p2 = void 0;
      var p3 = void 0;

      if (!isLoop) {
        p0 = points[idx === 0 ? idx : idx - 1];
        p2 = points[idx > len - 2 ? len - 1 : idx + 1];
        p3 = points[idx > len - 3 ? len - 1 : idx + 2];
      } else {
        p0 = points[(idx - 1 + len) % len];
        p2 = points[(idx + 1) % len];
        p3 = points[(idx + 2) % len];
      }

      var w2 = w * w;
      var w3 = w * w2;
      ret.push([interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3), interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)]);
    }

    return ret;
  }

  function smoothBezier(points, smooth, isLoop, constraint) {
    var cps = [];
    var v = [];
    var v1 = [];
    var v2 = [];
    var prevPoint;
    var nextPoint;
    var min$1;
    var max$1;

    if (constraint) {
      min$1 = [Infinity, Infinity];
      max$1 = [-Infinity, -Infinity];

      for (var i = 0, len = points.length; i < len; i++) {
        min(min$1, min$1, points[i]);
        max(max$1, max$1, points[i]);
      }

      min(min$1, min$1, constraint[0]);
      max(max$1, max$1, constraint[1]);
    }

    for (var i = 0, len = points.length; i < len; i++) {
      var point = points[i];

      if (isLoop) {
        prevPoint = points[i ? i - 1 : len - 1];
        nextPoint = points[(i + 1) % len];
      } else {
        if (i === 0 || i === len - 1) {
          cps.push(clone$1(points[i]));
          continue;
        } else {
          prevPoint = points[i - 1];
          nextPoint = points[i + 1];
        }
      }

      sub(v, nextPoint, prevPoint);
      scale(v, v, smooth);
      var d0 = distance(point, prevPoint);
      var d1 = distance(point, nextPoint);
      var sum = d0 + d1;

      if (sum !== 0) {
        d0 /= sum;
        d1 /= sum;
      }

      scale(v1, v, -d0);
      scale(v2, v, d1);
      var cp0 = add([], point, v1);
      var cp1 = add([], point, v2);

      if (constraint) {
        max(cp0, cp0, min$1);
        min(cp0, cp0, max$1);
        max(cp1, cp1, min$1);
        min(cp1, cp1, max$1);
      }

      cps.push(cp0);
      cps.push(cp1);
    }

    if (isLoop) {
      cps.push(cps.shift());
    }

    return cps;
  }

  function buildPath$1(ctx, shape, closePath) {
    var smooth = shape.smooth;
    var points = shape.points;

    if (points && points.length >= 2) {
      if (smooth && smooth !== 'spline') {
        var controlPoints = smoothBezier(points, smooth, closePath, shape.smoothConstraint);
        ctx.moveTo(points[0][0], points[0][1]);
        var len = points.length;

        for (var i = 0; i < (closePath ? len : len - 1); i++) {
          var cp1 = controlPoints[i * 2];
          var cp2 = controlPoints[i * 2 + 1];
          var p = points[(i + 1) % len];
          ctx.bezierCurveTo(cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]);
        }
      } else {
        if (smooth === 'spline') {
          points = smoothSpline(points, closePath);
        }

        ctx.moveTo(points[0][0], points[0][1]);

        for (var i = 1, l = points.length; i < l; i++) {
          ctx.lineTo(points[i][0], points[i][1]);
        }
      }

      closePath && ctx.closePath();
    }
  }

  var PolygonShape = function () {
    function PolygonShape() {
      this.points = null;
      this.smooth = 0;
      this.smoothConstraint = null;
    }

    return PolygonShape;
  }();

  var Polygon = function (_super) {
    __extends(Polygon, _super);

    function Polygon(opts) {
      return _super.call(this, opts) || this;
    }

    Polygon.prototype.getDefaultShape = function () {
      return new PolygonShape();
    };

    Polygon.prototype.buildPath = function (ctx, shape) {
      buildPath$1(ctx, shape, true);
    };

    return Polygon;
  }(Path);

  Polygon.prototype.type = 'polygon';

  var PolylineShape = function () {
    function PolylineShape() {
      this.points = null;
      this.percent = 1;
      this.smooth = 0;
      this.smoothConstraint = null;
    }

    return PolylineShape;
  }();

  var Polyline = function (_super) {
    __extends(Polyline, _super);

    function Polyline(opts) {
      return _super.call(this, opts) || this;
    }

    Polyline.prototype.getDefaultStyle = function () {
      return {
        stroke: '#000',
        fill: null
      };
    };

    Polyline.prototype.getDefaultShape = function () {
      return new PolylineShape();
    };

    Polyline.prototype.buildPath = function (ctx, shape) {
      buildPath$1(ctx, shape, false);
    };

    return Polyline;
  }(Path);

  Polyline.prototype.type = 'polyline';

  var Gradient = function () {
    function Gradient(colorStops) {
      this.colorStops = colorStops || [];
    }

    Gradient.prototype.addColorStop = function (offset, color) {
      this.colorStops.push({
        offset: offset,
        color: color
      });
    };

    return Gradient;
  }();

  var LinearGradient = function (_super) {
    __extends(LinearGradient, _super);

    function LinearGradient(x, y, x2, y2, colorStops, globalCoord) {
      var _this = _super.call(this, colorStops) || this;

      _this.x = x == null ? 0 : x;
      _this.y = y == null ? 0 : y;
      _this.x2 = x2 == null ? 1 : x2;
      _this.y2 = y2 == null ? 0 : y2;
      _this.type = 'linear';
      _this.global = globalCoord || false;
      return _this;
    }

    return LinearGradient;
  }(Gradient);

  var DEFAULT_TSPAN_STYLE = defaults({
    strokeFirst: true,
    font: DEFAULT_FONT,
    x: 0,
    y: 0,
    textAlign: 'left',
    textBaseline: 'top'
  }, DEFAULT_PATH_STYLE);

  var TSpan = function (_super) {
    __extends(TSpan, _super);

    function TSpan() {
      return _super !== null && _super.apply(this, arguments) || this;
    }

    TSpan.prototype.hasStroke = function () {
      var style = this.style;
      var stroke = style.stroke;
      return stroke != null && stroke !== 'none' && style.lineWidth > 0;
    };

    TSpan.prototype.hasFill = function () {
      var style = this.style;
      var fill = style.fill;
      return fill != null && fill !== 'none';
    };

    TSpan.prototype.createStyle = function (obj) {
      return createObject(DEFAULT_TSPAN_STYLE, obj);
    };

    TSpan.prototype.setBoundingRect = function (rect) {
      this._rect = rect;
    };

    TSpan.prototype.getBoundingRect = function () {
      var style = this.style;

      if (!this._rect) {
        var text = style.text;
        text != null ? text += '' : text = '';
        var rect = getBoundingRect(text, style.font, style.textAlign, style.textBaseline);
        rect.x += style.x || 0;
        rect.y += style.y || 0;

        if (this.hasStroke()) {
          var w = style.lineWidth;
          rect.x -= w / 2;
          rect.y -= w / 2;
          rect.width += w;
          rect.height += w;
        }

        this._rect = rect;
      }

      return this._rect;
    };

    return TSpan;
  }(Displayable);

  TSpan.prototype.type = 'tspan';

  function parseXML(svg) {
    if (isString(svg)) {
      var parser = new DOMParser();
      svg = parser.parseFromString(svg, 'text/xml');
    }

    var svgNode = svg;

    if (svgNode.nodeType === 9) {
      svgNode = svgNode.firstChild;
    }

    while (svgNode.nodeName.toLowerCase() !== 'svg' || svgNode.nodeType !== 1) {
      svgNode = svgNode.nextSibling;
    }

    return svgNode;
  }

  var CompoundPath = function (_super) {
    __extends(CompoundPath, _super);

    function CompoundPath() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = 'compound';
      return _this;
    }

    CompoundPath.prototype._updatePathDirty = function () {
      var paths = this.shape.paths;
      var dirtyPath = this.shapeChanged();

      for (var i = 0; i < paths.length; i++) {
        dirtyPath = dirtyPath || paths[i].shapeChanged();
      }

      if (dirtyPath) {
        this.dirtyShape();
      }
    };

    CompoundPath.prototype.beforeBrush = function () {
      this._updatePathDirty();

      var paths = this.shape.paths || [];
      var scale = this.getGlobalScale();

      for (var i = 0; i < paths.length; i++) {
        if (!paths[i].path) {
          paths[i].createPathProxy();
        }

        paths[i].path.setScale(scale[0], scale[1], paths[i].segmentIgnoreThreshold);
      }
    };

    CompoundPath.prototype.buildPath = function (ctx, shape) {
      var paths = shape.paths || [];

      for (var i = 0; i < paths.length; i++) {
        paths[i].buildPath(ctx, paths[i].shape, true);
      }
    };

    CompoundPath.prototype.afterBrush = function () {
      var paths = this.shape.paths || [];

      for (var i = 0; i < paths.length; i++) {
        paths[i].pathUpdated();
      }
    };

    CompoundPath.prototype.getBoundingRect = function () {
      this._updatePathDirty.call(this);

      return Path.prototype.getBoundingRect.call(this);
    };

    return CompoundPath;
  }(Path);

  var m = [];

  var IncrementalDisplayble = function (_super) {
    __extends(IncrementalDisplayble, _super);

    function IncrementalDisplayble() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.notClear = true;
      _this.incremental = true;
      _this._displayables = [];
      _this._temporaryDisplayables = [];
      _this._cursor = 0;
      return _this;
    }

    IncrementalDisplayble.prototype.traverse = function (cb, context) {
      cb.call(context, this);
    };

    IncrementalDisplayble.prototype.useStyle = function () {
      this.style = {};
    };

    IncrementalDisplayble.prototype.getCursor = function () {
      return this._cursor;
    };

    IncrementalDisplayble.prototype.innerAfterBrush = function () {
      this._cursor = this._displayables.length;
    };

    IncrementalDisplayble.prototype.clearDisplaybles = function () {
      this._displayables = [];
      this._temporaryDisplayables = [];
      this._cursor = 0;
      this.markRedraw();
      this.notClear = false;
    };

    IncrementalDisplayble.prototype.clearTemporalDisplayables = function () {
      this._temporaryDisplayables = [];
    };

    IncrementalDisplayble.prototype.addDisplayable = function (displayable, notPersistent) {
      if (notPersistent) {
        this._temporaryDisplayables.push(displayable);
      } else {
        this._displayables.push(displayable);
      }

      this.markRedraw();
    };

    IncrementalDisplayble.prototype.addDisplayables = function (displayables, notPersistent) {
      notPersistent = notPersistent || false;

      for (var i = 0; i < displayables.length; i++) {
        this.addDisplayable(displayables[i], notPersistent);
      }
    };

    IncrementalDisplayble.prototype.getDisplayables = function () {
      return this._displayables;
    };

    IncrementalDisplayble.prototype.getTemporalDisplayables = function () {
      return this._temporaryDisplayables;
    };

    IncrementalDisplayble.prototype.eachPendingDisplayable = function (cb) {
      for (var i = this._cursor; i < this._displayables.length; i++) {
        cb && cb(this._displayables[i]);
      }

      for (var i = 0; i < this._temporaryDisplayables.length; i++) {
        cb && cb(this._temporaryDisplayables[i]);
      }
    };

    IncrementalDisplayble.prototype.update = function () {
      this.updateTransform();

      for (var i = this._cursor; i < this._displayables.length; i++) {
        var displayable = this._displayables[i];
        displayable.parent = this;
        displayable.update();
        displayable.parent = null;
      }

      for (var i = 0; i < this._temporaryDisplayables.length; i++) {
        var displayable = this._temporaryDisplayables[i];
        displayable.parent = this;
        displayable.update();
        displayable.parent = null;
      }
    };

    IncrementalDisplayble.prototype.getBoundingRect = function () {
      if (!this._rect) {
        var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity);

        for (var i = 0; i < this._displayables.length; i++) {
          var displayable = this._displayables[i];
          var childRect = displayable.getBoundingRect().clone();

          if (displayable.needLocalTransform()) {
            childRect.applyTransform(displayable.getLocalTransform(m));
          }

          rect.union(childRect);
        }

        this._rect = rect;
      }

      return this._rect;
    };

    IncrementalDisplayble.prototype.contain = function (x, y) {
      var localPos = this.transformCoordToLocal(x, y);
      var rect = this.getBoundingRect();

      if (rect.contain(localPos[0], localPos[1])) {
        for (var i = 0; i < this._displayables.length; i++) {
          var displayable = this._displayables[i];

          if (displayable.contain(x, y)) {
            return true;
          }
        }
      }

      return false;
    };

    return IncrementalDisplayble;
  }(Displayable);

  var globalImageCache = new LRU(50);

  function findExistImage(newImageOrSrc) {
    if (typeof newImageOrSrc === 'string') {
      var cachedImgObj = globalImageCache.get(newImageOrSrc);
      return cachedImgObj && cachedImgObj.image;
    } else {
      return newImageOrSrc;
    }
  }

  function createOrUpdateImage(newImageOrSrc, image, hostEl, cb, cbPayload) {
    if (!newImageOrSrc) {
      return image;
    } else if (typeof newImageOrSrc === 'string') {
      if (image && image.__zrImageSrc === newImageOrSrc || !hostEl) {
        return image;
      }

      var cachedImgObj = globalImageCache.get(newImageOrSrc);
      var pendingWrap = {
        hostEl: hostEl,
        cb: cb,
        cbPayload: cbPayload
      };

      if (cachedImgObj) {
        image = cachedImgObj.image;
        !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);
      } else {
        image = new Image();
        image.onload = image.onerror = imageOnLoad;
        globalImageCache.put(newImageOrSrc, image.__cachedImgObj = {
          image: image,
          pending: [pendingWrap]
        });
        image.src = image.__zrImageSrc = newImageOrSrc;
      }

      return image;
    } else {
      return newImageOrSrc;
    }
  }

  function imageOnLoad() {
    var cachedImgObj = this.__cachedImgObj;
    this.onload = this.onerror = this.__cachedImgObj = null;

    for (var i = 0; i < cachedImgObj.pending.length; i++) {
      var pendingWrap = cachedImgObj.pending[i];
      var cb = pendingWrap.cb;
      cb && cb(this, pendingWrap.cbPayload);
      pendingWrap.hostEl.dirty();
    }

    cachedImgObj.pending.length = 0;
  }

  function isImageReady(image) {
    return image && image.width && image.height;
  }

  var STYLE_REG = /\{([a-zA-Z0-9_]+)\|([^}]*)\}/g;

  function truncateText(text, containerWidth, font, ellipsis, options) {
    if (!containerWidth) {
      return '';
    }

    var textLines = (text + '').split('\n');
    options = prepareTruncateOptions(containerWidth, font, ellipsis, options);

    for (var i = 0, len = textLines.length; i < len; i++) {
      textLines[i] = truncateSingleLine(textLines[i], options);
    }

    return textLines.join('\n');
  }

  function prepareTruncateOptions(containerWidth, font, ellipsis, options) {
    options = options || {};
    var preparedOpts = extend({}, options);
    preparedOpts.font = font;
    ellipsis = retrieve2(ellipsis, '...');
    preparedOpts.maxIterations = retrieve2(options.maxIterations, 2);
    var minChar = preparedOpts.minChar = retrieve2(options.minChar, 0);
    preparedOpts.cnCharWidth = getWidth('国', font);
    var ascCharWidth = preparedOpts.ascCharWidth = getWidth('a', font);
    preparedOpts.placeholder = retrieve2(options.placeholder, '');
    var contentWidth = containerWidth = Math.max(0, containerWidth - 1);

    for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {
      contentWidth -= ascCharWidth;
    }

    var ellipsisWidth = getWidth(ellipsis, font);

    if (ellipsisWidth > contentWidth) {
      ellipsis = '';
      ellipsisWidth = 0;
    }

    contentWidth = containerWidth - ellipsisWidth;
    preparedOpts.ellipsis = ellipsis;
    preparedOpts.ellipsisWidth = ellipsisWidth;
    preparedOpts.contentWidth = contentWidth;
    preparedOpts.containerWidth = containerWidth;
    return preparedOpts;
  }

  function truncateSingleLine(textLine, options) {
    var containerWidth = options.containerWidth;
    var font = options.font;
    var contentWidth = options.contentWidth;

    if (!containerWidth) {
      return '';
    }

    var lineWidth = getWidth(textLine, font);

    if (lineWidth <= containerWidth) {
      return textLine;
    }

    for (var j = 0;; j++) {
      if (lineWidth <= contentWidth || j >= options.maxIterations) {
        textLine += options.ellipsis;
        break;
      }

      var subLength = j === 0 ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth) : lineWidth > 0 ? Math.floor(textLine.length * contentWidth / lineWidth) : 0;
      textLine = textLine.substr(0, subLength);
      lineWidth = getWidth(textLine, font);
    }

    if (textLine === '') {
      textLine = options.placeholder;
    }

    return textLine;
  }

  function estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {
    var width = 0;
    var i = 0;

    for (var len = text.length; i < len && width < contentWidth; i++) {
      var charCode = text.charCodeAt(i);
      width += 0 <= charCode && charCode <= 127 ? ascCharWidth : cnCharWidth;
    }

    return i;
  }

  function parsePlainText(text, style) {
    text != null && (text += '');
    var overflow = style.overflow;
    var padding = style.padding;
    var font = style.font;
    var truncate = overflow === 'truncate';
    var calculatedLineHeight = getLineHeight(font);
    var lineHeight = retrieve2(style.lineHeight, calculatedLineHeight);
    var truncateLineOverflow = style.lineOverflow === 'truncate';
    var width = style.width;
    var lines;

    if (width != null && overflow === 'break' || overflow === 'breakAll') {
      lines = text ? wrapText(text, style.font, width, overflow === 'breakAll', 0).lines : [];
    } else {
      lines = text ? text.split('\n') : [];
    }

    var contentHeight = lines.length * lineHeight;
    var height = retrieve2(style.height, contentHeight);

    if (contentHeight > height && truncateLineOverflow) {
      var lineCount = Math.floor(height / lineHeight);
      lines = lines.slice(0, lineCount);
    }

    var outerHeight = height;
    var outerWidth = width;

    if (padding) {
      outerHeight += padding[0] + padding[2];

      if (outerWidth != null) {
        outerWidth += padding[1] + padding[3];
      }
    }

    if (text && truncate && outerWidth != null) {
      var options = prepareTruncateOptions(width, font, style.ellipsis, {
        minChar: style.truncateMinChar,
        placeholder: style.placeholder
      });

      for (var i = 0; i < lines.length; i++) {
        lines[i] = truncateSingleLine(lines[i], options);
      }
    }

    if (width == null) {
      var maxWidth = 0;

      for (var i = 0; i < lines.length; i++) {
        maxWidth = Math.max(getWidth(lines[i], font), maxWidth);
      }

      width = maxWidth;
    }

    return {
      lines: lines,
      height: height,
      outerHeight: outerHeight,
      lineHeight: lineHeight,
      calculatedLineHeight: calculatedLineHeight,
      contentHeight: contentHeight,
      width: width
    };
  }

  var RichTextToken = function () {
    function RichTextToken() {}

    return RichTextToken;
  }();

  var RichTextLine = function () {
    function RichTextLine(tokens) {
      this.tokens = [];

      if (tokens) {
        this.tokens = tokens;
      }
    }

    return RichTextLine;
  }();

  var RichTextContentBlock = function () {
    function RichTextContentBlock() {
      this.width = 0;
      this.height = 0;
      this.contentWidth = 0;
      this.contentHeight = 0;
      this.outerWidth = 0;
      this.outerHeight = 0;
      this.lines = [];
    }

    return RichTextContentBlock;
  }();

  function parseRichText(text, style) {
    var contentBlock = new RichTextContentBlock();
    text != null && (text += '');

    if (!text) {
      return contentBlock;
    }

    var topWidth = style.width;
    var topHeight = style.height;
    var overflow = style.overflow;
    var wrapInfo = (overflow === 'break' || overflow === 'breakAll') && topWidth != null ? {
      width: topWidth,
      accumWidth: 0,
      breakAll: overflow === 'breakAll'
    } : null;
    var lastIndex = STYLE_REG.lastIndex = 0;
    var result;

    while ((result = STYLE_REG.exec(text)) != null) {
      var matchedIndex = result.index;

      if (matchedIndex > lastIndex) {
        pushTokens(contentBlock, text.substring(lastIndex, matchedIndex), style, wrapInfo);
      }

      pushTokens(contentBlock, result[2], style, wrapInfo, result[1]);
      lastIndex = STYLE_REG.lastIndex;
    }

    if (lastIndex < text.length) {
      pushTokens(contentBlock, text.substring(lastIndex, text.length), style, wrapInfo);
    }

    var pendingList = [];
    var calculatedHeight = 0;
    var calculatedWidth = 0;
    var stlPadding = style.padding;
    var truncate = overflow === 'truncate';
    var truncateLine = style.lineOverflow === 'truncate';

    outer: for (var i = 0; i < contentBlock.lines.length; i++) {
      var line = contentBlock.lines[i];
      var lineHeight = 0;
      var lineWidth = 0;

      for (var j = 0; j < line.tokens.length; j++) {
        var token = line.tokens[j];
        var tokenStyle = token.styleName && style.rich[token.styleName] || {};
        var textPadding = token.textPadding = tokenStyle.padding;
        var paddingH = textPadding ? textPadding[1] + textPadding[3] : 0;
        var font = token.font = tokenStyle.font || style.font;
        token.contentHeight = getLineHeight(font);
        var tokenHeight = retrieve2(tokenStyle.height, token.contentHeight);
        token.lineHeight = retrieve3(tokenStyle.lineHeight, style.lineHeight, tokenHeight);
        textPadding && (tokenHeight += textPadding[0] + textPadding[2]);
        token.height = tokenHeight;
        token.align = tokenStyle && tokenStyle.align || style.align;
        token.verticalAlign = tokenStyle && tokenStyle.verticalAlign || 'middle';

        if (truncateLine && topHeight != null && calculatedHeight + token.lineHeight > topHeight) {
          if (j > 0) {
            line.tokens = line.tokens.slice(0, j);
            contentBlock.lines = contentBlock.lines.slice(0, i + 1);
          } else {
            contentBlock.lines = contentBlock.lines.slice(0, i);
          }

          break outer;
        }

        var styleTokenWidth = tokenStyle.width;
        var tokenWidthNotSpecified = styleTokenWidth == null || styleTokenWidth === 'auto';

        if (typeof styleTokenWidth === 'string' && styleTokenWidth.charAt(styleTokenWidth.length - 1) === '%') {
          token.percentWidth = styleTokenWidth;
          pendingList.push(token);
          token.contentWidth = getWidth(token.text, font);
        } else {
          if (tokenWidthNotSpecified) {
            var textBackgroundColor = tokenStyle.backgroundColor;
            var bgImg = textBackgroundColor && textBackgroundColor.image;

            if (bgImg) {
              bgImg = findExistImage(bgImg);

              if (isImageReady(bgImg)) {
                token.width = Math.max(token.width, bgImg.width * tokenHeight / bgImg.height);
              }
            }
          }

          var remainTruncWidth = truncate && topWidth != null ? topWidth - lineWidth : null;

          if (remainTruncWidth != null && remainTruncWidth < token.width) {
            if (!tokenWidthNotSpecified || remainTruncWidth < paddingH) {
              token.text = '';
              token.width = token.contentWidth = 0;
            } else {
              token.text = truncateText(token.text, remainTruncWidth - paddingH, font, style.ellipsis, {
                minChar: style.truncateMinChar
              });
              token.width = token.contentWidth = getWidth(token.text, font);
            }
          } else {
            token.contentWidth = getWidth(token.text, font);
          }
        }

        token.width += paddingH;
        lineWidth += token.width;
        tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));
      }

      line.width = lineWidth;
      line.lineHeight = lineHeight;
      calculatedHeight += lineHeight;
      calculatedWidth = Math.max(calculatedWidth, lineWidth);
    }

    contentBlock.outerWidth = contentBlock.width = retrieve2(topWidth, calculatedWidth);
    contentBlock.outerHeight = contentBlock.height = retrieve2(topHeight, calculatedHeight);
    contentBlock.contentHeight = calculatedHeight;
    contentBlock.contentWidth = calculatedWidth;

    if (stlPadding) {
      contentBlock.outerWidth += stlPadding[1] + stlPadding[3];
      contentBlock.outerHeight += stlPadding[0] + stlPadding[2];
    }

    for (var i = 0; i < pendingList.length; i++) {
      var token = pendingList[i];
      var percentWidth = token.percentWidth;
      token.width = parseInt(percentWidth, 10) / 100 * contentBlock.width;
    }

    return contentBlock;
  }

  function pushTokens(block, str, style, wrapInfo, styleName) {
    var isEmptyStr = str === '';
    var tokenStyle = styleName && style.rich[styleName] || {};
    var lines = block.lines;
    var font = tokenStyle.font || style.font;
    var newLine = false;
    var strLines;
    var linesWidths;

    if (wrapInfo) {
      var tokenPadding = tokenStyle.padding;
      var tokenPaddingH = tokenPadding ? tokenPadding[1] + tokenPadding[3] : 0;

      if (tokenStyle.width != null && tokenStyle.width !== 'auto') {
        var outerWidth_1 = parsePercent$1(tokenStyle.width, wrapInfo.width) + tokenPaddingH;

        if (lines.length > 0) {
          if (outerWidth_1 + wrapInfo.accumWidth > wrapInfo.width) {
            strLines = str.split('\n');
            newLine = true;
          }
        }

        wrapInfo.accumWidth = outerWidth_1;
      } else {
        var res = wrapText(str, font, wrapInfo.width, wrapInfo.breakAll, wrapInfo.accumWidth);
        wrapInfo.accumWidth = res.accumWidth + tokenPaddingH;
        linesWidths = res.linesWidths;
        strLines = res.lines;
      }
    } else {
      strLines = str.split('\n');
    }

    for (var i = 0; i < strLines.length; i++) {
      var text = strLines[i];
      var token = new RichTextToken();
      token.styleName = styleName;
      token.text = text;
      token.isLineHolder = !text && !isEmptyStr;

      if (typeof tokenStyle.width === 'number') {
        token.width = tokenStyle.width;
      } else {
        token.width = linesWidths ? linesWidths[i] : getWidth(text, font);
      }

      if (!i && !newLine) {
        var tokens = (lines[lines.length - 1] || (lines[0] = new RichTextLine())).tokens;
        var tokensLen = tokens.length;
        tokensLen === 1 && tokens[0].isLineHolder ? tokens[0] = token : (text || !tokensLen || isEmptyStr) && tokens.push(token);
      } else {
        lines.push(new RichTextLine([token]));
      }
    }
  }

  function isLatin(ch) {
    var code = ch.charCodeAt(0);
    return code >= 0x21 && code <= 0xFF;
  }

  var breakCharMap = reduce(',&?/;] '.split(''), function (obj, ch) {
    obj[ch] = true;
    return obj;
  }, {});

  function isWordBreakChar(ch) {
    if (isLatin(ch)) {
      if (breakCharMap[ch]) {
        return true;
      }

      return false;
    }

    return true;
  }

  function wrapText(text, font, lineWidth, isBreakAll, lastAccumWidth) {
    var lines = [];
    var linesWidths = [];
    var line = '';
    var currentWord = '';
    var currentWordWidth = 0;
    var accumWidth = 0;

    for (var i = 0; i < text.length; i++) {
      var ch = text.charAt(i);

      if (ch === '\n') {
        if (currentWord) {
          line += currentWord;
          accumWidth += currentWordWidth;
        }

        lines.push(line);
        linesWidths.push(accumWidth);
        line = '';
        currentWord = '';
        currentWordWidth = 0;
        accumWidth = 0;
        continue;
      }

      var chWidth = getWidth(ch, font);
      var inWord = isBreakAll ? false : !isWordBreakChar(ch);

      if (!lines.length ? lastAccumWidth + accumWidth + chWidth > lineWidth : accumWidth + chWidth > lineWidth) {
        if (!accumWidth) {
          if (inWord) {
            lines.push(currentWord);
            linesWidths.push(currentWordWidth);
            currentWord = ch;
            currentWordWidth = chWidth;
          } else {
            lines.push(ch);
            linesWidths.push(chWidth);
          }
        } else if (line || currentWord) {
          if (inWord) {
            if (!line) {
              line = currentWord;
              currentWord = '';
              currentWordWidth = 0;
              accumWidth = currentWordWidth;
            }

            lines.push(line);
            linesWidths.push(accumWidth - currentWordWidth);
            currentWord += ch;
            currentWordWidth += chWidth;
            line = '';
            accumWidth = currentWordWidth;
          } else {
            if (currentWord) {
              line += currentWord;
              accumWidth += currentWordWidth;
              currentWord = '';
              currentWordWidth = 0;
            }

            lines.push(line);
            linesWidths.push(accumWidth);
            line = ch;
            accumWidth = chWidth;
          }
        }

        continue;
      }

      accumWidth += chWidth;

      if (inWord) {
        currentWord += ch;
        currentWordWidth += chWidth;
      } else {
        if (currentWord) {
          line += currentWord;
          currentWord = '';
          currentWordWidth = 0;
        }

        line += ch;
      }
    }

    if (!lines.length && !line) {
      line = text;
      currentWord = '';
      currentWordWidth = 0;
    }

    if (currentWord) {
      line += currentWord;
    }

    if (line) {
      lines.push(line);
      linesWidths.push(accumWidth);
    }

    if (lines.length === 1) {
      accumWidth += lastAccumWidth;
    }

    return {
      accumWidth: accumWidth,
      lines: lines,
      linesWidths: linesWidths
    };
  }

  function parsePercent$1(value, maxValue) {
    if (typeof value === 'string') {
      if (value.lastIndexOf('%') >= 0) {
        return parseFloat(value) / 100 * maxValue;
      }

      return parseFloat(value);
    }

    return value;
  }

  var DEFAULT_RICH_TEXT_COLOR = {
    fill: '#000'
  };
  var DEFAULT_STROKE_LINE_WIDTH = 2;
  var DEFAULT_TEXT_ANIMATION_PROPS = {
    style: defaults({
      fill: true,
      stroke: true,
      fillOpacity: true,
      strokeOpacity: true,
      lineWidth: true,
      fontSize: true,
      lineHeight: true,
      width: true,
      height: true,
      textShadowColor: true,
      textShadowBlur: true,
      textShadowOffsetX: true,
      textShadowOffsetY: true,
      backgroundColor: true,
      padding: true,
      borderColor: true,
      borderWidth: true,
      borderRadius: true
    }, DEFAULT_COMMON_ANIMATION_PROPS.style)
  };

  var ZRText = function (_super) {
    __extends(ZRText, _super);

    function ZRText(opts) {
      var _this = _super.call(this) || this;

      _this.type = 'text';
      _this._children = [];
      _this._defaultStyle = DEFAULT_RICH_TEXT_COLOR;

      _this.attr(opts);

      return _this;
    }

    ZRText.prototype.childrenRef = function () {
      return this._children;
    };

    ZRText.prototype.update = function () {
      if (this.styleChanged()) {
        this._updateSubTexts();
      }

      for (var i = 0; i < this._children.length; i++) {
        var child = this._children[i];
        child.zlevel = this.zlevel;
        child.z = this.z;
        child.z2 = this.z2;
        child.culling = this.culling;
        child.cursor = this.cursor;
        child.invisible = this.invisible;
      }

      var attachedTransform = this.attachedTransform;

      if (attachedTransform) {
        attachedTransform.updateTransform();
        var m = attachedTransform.transform;

        if (m) {
          this.transform = this.transform || [];
          copy$1(this.transform, m);
        } else {
          this.transform = null;
        }
      } else {
        _super.prototype.update.call(this);
      }
    };

    ZRText.prototype.getComputedTransform = function () {
      if (this.__hostTarget) {
        this.__hostTarget.getComputedTransform();

        this.__hostTarget.updateInnerText(true);
      }

      return this.attachedTransform ? this.attachedTransform.getComputedTransform() : _super.prototype.getComputedTransform.call(this);
    };

    ZRText.prototype._updateSubTexts = function () {
      this._childCursor = 0;
      normalizeTextStyle(this.style);
      this.style.rich ? this._updateRichTexts() : this._updatePlainTexts();
      this._children.length = this._childCursor;
      this.styleUpdated();
    };

    ZRText.prototype.addSelfToZr = function (zr) {
      _super.prototype.addSelfToZr.call(this, zr);

      for (var i = 0; i < this._children.length; i++) {
        this._children[i].__zr = zr;
      }
    };

    ZRText.prototype.removeSelfFromZr = function (zr) {
      _super.prototype.removeSelfFromZr.call(this, zr);

      for (var i = 0; i < this._children.length; i++) {
        this._children[i].__zr = null;
      }
    };

    ZRText.prototype.getBoundingRect = function () {
      if (this.styleChanged()) {
        this._updateSubTexts();
      }

      if (!this._rect) {
        var tmpRect = new BoundingRect(0, 0, 0, 0);
        var children = this._children;
        var tmpMat = [];
        var rect = null;

        for (var i = 0; i < children.length; i++) {
          var child = children[i];
          var childRect = child.getBoundingRect();
          var transform = child.getLocalTransform(tmpMat);

          if (transform) {
            tmpRect.copy(childRect);
            tmpRect.applyTransform(transform);
            rect = rect || tmpRect.clone();
            rect.union(tmpRect);
          } else {
            rect = rect || childRect.clone();
            rect.union(childRect);
          }
        }

        this._rect = rect || tmpRect;
      }

      return this._rect;
    };

    ZRText.prototype.setDefaultTextStyle = function (defaultTextStyle) {
      this._defaultStyle = defaultTextStyle || DEFAULT_RICH_TEXT_COLOR;
    };

    ZRText.prototype.setTextContent = function (textContent) {
      throw new Error('Can\'t attach text on another text');
    };

    ZRText.prototype._mergeStyle = function (targetStyle, sourceStyle) {
      if (!sourceStyle) {
        return targetStyle;
      }

      var sourceRich = sourceStyle.rich;
      var targetRich = targetStyle.rich || sourceRich && {};
      extend(targetStyle, sourceStyle);

      if (sourceRich && targetRich) {
        this._mergeRich(targetRich, sourceRich);

        targetStyle.rich = targetRich;
      } else if (targetRich) {
        targetStyle.rich = targetRich;
      }

      return targetStyle;
    };

    ZRText.prototype._mergeRich = function (targetRich, sourceRich) {
      var richNames = keys(sourceRich);

      for (var i = 0; i < richNames.length; i++) {
        var richName = richNames[i];
        targetRich[richName] = targetRich[richName] || {};
        extend(targetRich[richName], sourceRich[richName]);
      }
    };

    ZRText.prototype._getAnimationStyleProps = function () {
      return DEFAULT_TEXT_ANIMATION_PROPS;
    };

    ZRText.prototype._getOrCreateChild = function (Ctor) {
      var child = this._children[this._childCursor];

      if (!child || !(child instanceof Ctor)) {
        child = new Ctor();
      }

      this._children[this._childCursor++] = child;
      child.__zr = this.__zr;
      child.parent = this;
      return child;
    };

    ZRText.prototype._updatePlainTexts = function () {
      var style = this.style;
      var textFont = style.font || DEFAULT_FONT;
      var textPadding = style.padding;
      var text = getStyleText(style);
      var contentBlock = parsePlainText(text, style);
      var needDrawBg = needDrawBackground(style);
      var bgColorDrawn = !!style.backgroundColor;
      var outerHeight = contentBlock.outerHeight;
      var textLines = contentBlock.lines;
      var lineHeight = contentBlock.lineHeight;
      var defaultStyle = this._defaultStyle;
      var baseX = style.x || 0;
      var baseY = style.y || 0;
      var textAlign = style.align || defaultStyle.align || 'left';
      var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign || 'top';
      var textX = baseX;
      var textY = adjustTextY(baseY, contentBlock.contentHeight, verticalAlign);

      if (needDrawBg || textPadding) {
        var outerWidth_1 = contentBlock.width;
        textPadding && (outerWidth_1 += textPadding[1] + textPadding[3]);
        var boxX = adjustTextX(baseX, outerWidth_1, textAlign);
        var boxY = adjustTextY(baseY, outerHeight, verticalAlign);
        needDrawBg && this._renderBackground(style, boxX, boxY, outerWidth_1, outerHeight);
      }

      textY += lineHeight / 2;

      if (textPadding) {
        textX = getTextXForPadding(baseX, textAlign, textPadding);

        if (verticalAlign === 'top') {
          textY += textPadding[0];
        } else if (verticalAlign === 'bottom') {
          textY -= textPadding[2];
        }
      }

      var defaultLineWidth = 0;
      var useDefaultFill = false;
      var textFill = getFill('fill' in style ? style.fill : (useDefaultFill = true, defaultStyle.fill));
      var textStroke = getStroke('stroke' in style ? style.stroke : !bgColorDrawn && (!defaultStyle.autoStroke || useDefaultFill) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke) : null);
      var hasShadow = style.textShadowBlur > 0;
      var fixedBoundingRect = style.width != null && (style.overflow === 'truncate' || style.overflow === 'break' || style.overflow === 'breakAll');
      var calculatedLineHeight = contentBlock.calculatedLineHeight;

      for (var i = 0; i < textLines.length; i++) {
        var el = this._getOrCreateChild(TSpan);

        var subElStyle = el.createStyle();
        el.useStyle(subElStyle);
        subElStyle.text = textLines[i];
        subElStyle.x = textX;
        subElStyle.y = textY;

        if (textAlign) {
          subElStyle.textAlign = textAlign;
        }

        subElStyle.textBaseline = 'middle';
        subElStyle.opacity = style.opacity;
        subElStyle.strokeFirst = true;

        if (hasShadow) {
          subElStyle.shadowBlur = style.textShadowBlur || 0;
          subElStyle.shadowColor = style.textShadowColor || 'transparent';
          subElStyle.shadowOffsetX = style.textShadowOffsetX || 0;
          subElStyle.shadowOffsetY = style.textShadowOffsetY || 0;
        }

        if (textStroke) {
          subElStyle.stroke = textStroke;
          subElStyle.lineWidth = style.lineWidth || defaultLineWidth;
          subElStyle.lineDash = style.lineDash;
          subElStyle.lineDashOffset = style.lineDashOffset || 0;
        }

        if (textFill) {
          subElStyle.fill = textFill;
        }

        subElStyle.font = textFont;
        textY += lineHeight;

        if (fixedBoundingRect) {
          el.setBoundingRect(new BoundingRect(adjustTextX(subElStyle.x, style.width, subElStyle.textAlign), adjustTextY(subElStyle.y, calculatedLineHeight, subElStyle.textBaseline), style.width, calculatedLineHeight));
        }
      }
    };

    ZRText.prototype._updateRichTexts = function () {
      var style = this.style;
      var text = getStyleText(style);
      var contentBlock = parseRichText(text, style);
      var contentWidth = contentBlock.width;
      var outerWidth = contentBlock.outerWidth;
      var outerHeight = contentBlock.outerHeight;
      var textPadding = style.padding;
      var baseX = style.x || 0;
      var baseY = style.y || 0;
      var defaultStyle = this._defaultStyle;
      var textAlign = style.align || defaultStyle.align;
      var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign;
      var boxX = adjustTextX(baseX, outerWidth, textAlign);
      var boxY = adjustTextY(baseY, outerHeight, verticalAlign);
      var xLeft = boxX;
      var lineTop = boxY;

      if (textPadding) {
        xLeft += textPadding[3];
        lineTop += textPadding[0];
      }

      var xRight = xLeft + contentWidth;

      if (needDrawBackground(style)) {
        this._renderBackground(style, boxX, boxY, outerWidth, outerHeight);
      }

      var bgColorDrawn = !!style.backgroundColor;

      for (var i = 0; i < contentBlock.lines.length; i++) {
        var line = contentBlock.lines[i];
        var tokens = line.tokens;
        var tokenCount = tokens.length;
        var lineHeight = line.lineHeight;
        var remainedWidth = line.width;
        var leftIndex = 0;
        var lineXLeft = xLeft;
        var lineXRight = xRight;
        var rightIndex = tokenCount - 1;
        var token = void 0;

        while (leftIndex < tokenCount && (token = tokens[leftIndex], !token.align || token.align === 'left')) {
          this._placeToken(token, style, lineHeight, lineTop, lineXLeft, 'left', bgColorDrawn);

          remainedWidth -= token.width;
          lineXLeft += token.width;
          leftIndex++;
        }

        while (rightIndex >= 0 && (token = tokens[rightIndex], token.align === 'right')) {
          this._placeToken(token, style, lineHeight, lineTop, lineXRight, 'right', bgColorDrawn);

          remainedWidth -= token.width;
          lineXRight -= token.width;
          rightIndex--;
        }

        lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - remainedWidth) / 2;

        while (leftIndex <= rightIndex) {
          token = tokens[leftIndex];

          this._placeToken(token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center', bgColorDrawn);

          lineXLeft += token.width;
          leftIndex++;
        }

        lineTop += lineHeight;
      }
    };

    ZRText.prototype._placeToken = function (token, style, lineHeight, lineTop, x, textAlign, parentBgColorDrawn) {
      var tokenStyle = style.rich[token.styleName] || {};
      tokenStyle.text = token.text;
      var verticalAlign = token.verticalAlign;
      var y = lineTop + lineHeight / 2;

      if (verticalAlign === 'top') {
        y = lineTop + token.height / 2;
      } else if (verticalAlign === 'bottom') {
        y = lineTop + lineHeight - token.height / 2;
      }

      var needDrawBg = !token.isLineHolder && needDrawBackground(tokenStyle);
      needDrawBg && this._renderBackground(tokenStyle, textAlign === 'right' ? x - token.width : textAlign === 'center' ? x - token.width / 2 : x, y - token.height / 2, token.width, token.height);
      var bgColorDrawn = !!tokenStyle.backgroundColor;
      var textPadding = token.textPadding;

      if (textPadding) {
        x = getTextXForPadding(x, textAlign, textPadding);
      }

      var el = this._getOrCreateChild(TSpan);

      var subElStyle = el.createStyle();
      el.useStyle(subElStyle);
      var defaultStyle = this._defaultStyle;
      var useDefaultFill = false;
      var defaultLineWidth = 0;
      var textFill = getStroke('fill' in tokenStyle ? tokenStyle.fill : 'fill' in style ? style.fill : (useDefaultFill = true, defaultStyle.fill));
      var textStroke = getStroke('stroke' in tokenStyle ? tokenStyle.stroke : 'stroke' in style ? style.stroke : !bgColorDrawn && !parentBgColorDrawn && (!defaultStyle.autoStroke || useDefaultFill) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke) : null);
      var hasShadow = tokenStyle.textShadowBlur > 0 || style.textShadowBlur > 0;
      subElStyle.text = token.text;
      subElStyle.x = x;
      subElStyle.y = y;

      if (hasShadow) {
        subElStyle.shadowBlur = tokenStyle.textShadowBlur || style.textShadowBlur || 0;
        subElStyle.shadowColor = tokenStyle.textShadowColor || style.textShadowColor || 'transparent';
        subElStyle.shadowOffsetX = tokenStyle.textShadowOffsetX || style.textShadowOffsetX || 0;
        subElStyle.shadowOffsetY = tokenStyle.textShadowOffsetY || style.textShadowOffsetY || 0;
      }

      subElStyle.textAlign = textAlign;
      subElStyle.textBaseline = 'middle';
      subElStyle.font = token.font || DEFAULT_FONT;

      if (textStroke) {
        subElStyle.lineWidth = retrieve3(tokenStyle.lineWidth, style.lineWidth, defaultLineWidth);
        subElStyle.lineDash = retrieve2(tokenStyle.lineDash, style.lineDash);
        subElStyle.lineDashOffset = style.lineDashOffset || 0;
        subElStyle.stroke = textStroke;
      }

      if (textFill) {
        subElStyle.fill = textFill;
      }

      var textWidth = token.contentWidth;
      var textHeight = token.contentHeight;
      el.setBoundingRect(new BoundingRect(adjustTextX(subElStyle.x, textWidth, subElStyle.textAlign), adjustTextY(subElStyle.y, textHeight, subElStyle.textBaseline), textWidth, textHeight));
    };

    ZRText.prototype._renderBackground = function (style, x, y, width, height) {
      var textBackgroundColor = style.backgroundColor;
      var textBorderWidth = style.borderWidth;
      var textBorderColor = style.borderColor;
      var isPlainBg = isString(textBackgroundColor);
      var textBorderRadius = style.borderRadius;
      var self = this;
      var rectEl;
      var imgEl;

      if (isPlainBg || textBorderWidth && textBorderColor) {
        rectEl = this._getOrCreateChild(Rect);
        rectEl.useStyle(rectEl.createStyle());
        rectEl.style.fill = null;
        var rectShape = rectEl.shape;
        rectShape.x = x;
        rectShape.y = y;
        rectShape.width = width;
        rectShape.height = height;
        rectShape.r = textBorderRadius;
        rectEl.dirtyShape();
      }

      if (isPlainBg) {
        var rectStyle = rectEl.style;
        rectStyle.fill = textBackgroundColor || null;
        rectStyle.opacity = retrieve2(style.opacity, 1);
        rectStyle.fillOpacity = retrieve2(style.fillOpacity, 1);
      } else if (textBackgroundColor && textBackgroundColor.image) {
        imgEl = this._getOrCreateChild(ZRImage);

        imgEl.onload = function () {
          self.dirtyStyle();
        };

        var imgStyle = imgEl.style;
        imgStyle.image = textBackgroundColor.image;
        imgStyle.x = x;
        imgStyle.y = y;
        imgStyle.width = width;
        imgStyle.height = height;
      }

      if (textBorderWidth && textBorderColor) {
        var rectStyle = rectEl.style;
        rectStyle.lineWidth = textBorderWidth;
        rectStyle.stroke = textBorderColor;
        rectStyle.strokeOpacity = retrieve2(style.strokeOpacity, 1);
        rectStyle.lineDash = style.borderDash;
        rectStyle.lineDashOffset = style.borderDashOffset || 0;

        if (rectEl.hasFill() && rectEl.hasStroke()) {
          rectStyle.strokeFirst = true;
          rectStyle.lineWidth *= 2;
        }
      }

      var shadowStyle = (rectEl || imgEl).style;
      shadowStyle.shadowBlur = style.shadowBlur || 0;
      shadowStyle.shadowColor = style.shadowColor || 'transparent';
      shadowStyle.shadowOffsetX = style.shadowOffsetX || 0;
      shadowStyle.shadowOffsetY = style.shadowOffsetY || 0;
    };

    ZRText.makeFont = function (style) {
      var font = '';

      if (style.fontSize || style.fontFamily || style.fontWeight) {
        var fontSize = '';

        if (typeof style.fontSize === 'string' && (style.fontSize.indexOf('px') !== -1 || style.fontSize.indexOf('rem') !== -1 || style.fontSize.indexOf('em') !== -1)) {
          fontSize = style.fontSize;
        } else if (!isNaN(+style.fontSize)) {
          fontSize = style.fontSize + 'px';
        } else {
          fontSize = '12px';
        }

        font = [style.fontStyle, style.fontWeight, fontSize, style.fontFamily || 'sans-serif'].join(' ');
      }

      return font && trim(font) || style.textFont || style.font;
    };

    return ZRText;
  }(Displayable);

  var VALID_TEXT_ALIGN = {
    left: true,
    right: 1,
    center: 1
  };
  var VALID_TEXT_VERTICAL_ALIGN = {
    top: 1,
    bottom: 1,
    middle: 1
  };

  function normalizeTextStyle(style) {
    normalizeStyle(style);
    each(style.rich, normalizeStyle);
    return style;
  }

  function normalizeStyle(style) {
    if (style) {
      style.font = ZRText.makeFont(style);
      var textAlign = style.align;
      textAlign === 'middle' && (textAlign = 'center');
      style.align = textAlign == null || VALID_TEXT_ALIGN[textAlign] ? textAlign : 'left';
      var verticalAlign = style.verticalAlign;
      verticalAlign === 'center' && (verticalAlign = 'middle');
      style.verticalAlign = verticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[verticalAlign] ? verticalAlign : 'top';
      var textPadding = style.padding;

      if (textPadding) {
        style.padding = normalizeCssArray(style.padding);
      }
    }
  }

  function getStroke(stroke, lineWidth) {
    return stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none' ? null : stroke.image || stroke.colorStops ? '#000' : stroke;
  }

  function getFill(fill) {
    return fill == null || fill === 'none' ? null : fill.image || fill.colorStops ? '#000' : fill;
  }

  function getTextXForPadding(x, textAlign, textPadding) {
    return textAlign === 'right' ? x - textPadding[1] : textAlign === 'center' ? x + textPadding[3] / 2 - textPadding[1] / 2 : x + textPadding[3];
  }

  function getStyleText(style) {
    var text = style.text;
    text != null && (text += '');
    return text;
  }

  function needDrawBackground(style) {
    return !!(style.backgroundColor || style.borderWidth && style.borderColor);
  }

  var ArcShape = function () {
    function ArcShape() {
      this.cx = 0;
      this.cy = 0;
      this.r = 0;
      this.startAngle = 0;
      this.endAngle = Math.PI * 2;
      this.clockwise = true;
    }

    return ArcShape;
  }();

  var Arc = function (_super) {
    __extends(Arc, _super);

    function Arc(opts) {
      return _super.call(this, opts) || this;
    }

    Arc.prototype.getDefaultStyle = function () {
      return {
        stroke: '#000',
        fill: null
      };
    };

    Arc.prototype.getDefaultShape = function () {
      return new ArcShape();
    };

    Arc.prototype.buildPath = function (ctx, shape) {
      var x = shape.cx;
      var y = shape.cy;
      var r = Math.max(shape.r, 0);
      var startAngle = shape.startAngle;
      var endAngle = shape.endAngle;
      var clockwise = shape.clockwise;
      var unitX = Math.cos(startAngle);
      var unitY = Math.sin(startAngle);
      ctx.moveTo(unitX * r + x, unitY * r + y);
      ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
    };

    return Arc;
  }(Path);

  Arc.prototype.type = 'arc';
  var out = [];

  var BezierCurveShape = function () {
    function BezierCurveShape() {
      this.x1 = 0;
      this.y1 = 0;
      this.x2 = 0;
      this.y2 = 0;
      this.cpx1 = 0;
      this.cpy1 = 0;
      this.percent = 1;
    }

    return BezierCurveShape;
  }();

  function someVectorAt(shape, t, isTangent) {
    var cpx2 = shape.cpx2;
    var cpy2 = shape.cpy2;

    if (cpx2 === null || cpy2 === null) {
      return [(isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t), (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)];
    } else {
      return [(isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t), (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)];
    }
  }

  var BezierCurve = function (_super) {
    __extends(BezierCurve, _super);

    function BezierCurve(opts) {
      return _super.call(this, opts) || this;
    }

    BezierCurve.prototype.getDefaultStyle = function () {
      return {
        stroke: '#000',
        fill: null
      };
    };

    BezierCurve.prototype.getDefaultShape = function () {
      return new BezierCurveShape();
    };

    BezierCurve.prototype.buildPath = function (ctx, shape) {
      var x1 = shape.x1;
      var y1 = shape.y1;
      var x2 = shape.x2;
      var y2 = shape.y2;
      var cpx1 = shape.cpx1;
      var cpy1 = shape.cpy1;
      var cpx2 = shape.cpx2;
      var cpy2 = shape.cpy2;
      var percent = shape.percent;

      if (percent === 0) {
        return;
      }

      ctx.moveTo(x1, y1);

      if (cpx2 == null || cpy2 == null) {
        if (percent < 1) {
          quadraticSubdivide(x1, cpx1, x2, percent, out);
          cpx1 = out[1];
          x2 = out[2];
          quadraticSubdivide(y1, cpy1, y2, percent, out);
          cpy1 = out[1];
          y2 = out[2];
        }

        ctx.quadraticCurveTo(cpx1, cpy1, x2, y2);
      } else {
        if (percent < 1) {
          cubicSubdivide(x1, cpx1, cpx2, x2, percent, out);
          cpx1 = out[1];
          cpx2 = out[2];
          x2 = out[3];
          cubicSubdivide(y1, cpy1, cpy2, y2, percent, out);
          cpy1 = out[1];
          cpy2 = out[2];
          y2 = out[3];
        }

        ctx.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x2, y2);
      }
    };

    BezierCurve.prototype.pointAt = function (t) {
      return someVectorAt(this.shape, t, false);
    };

    BezierCurve.prototype.tangentAt = function (t) {
      var p = someVectorAt(this.shape, t, true);
      return normalize(p, p);
    };

    return BezierCurve;
  }(Path);

  BezierCurve.prototype.type = 'bezier-curve';

  var DropletShape = function () {
    function DropletShape() {
      this.cx = 0;
      this.cy = 0;
      this.width = 0;
      this.height = 0;
    }

    return DropletShape;
  }();

  var Droplet = function (_super) {
    __extends(Droplet, _super);

    function Droplet(opts) {
      return _super.call(this, opts) || this;
    }

    Droplet.prototype.getDefaultShape = function () {
      return new DropletShape();
    };

    Droplet.prototype.buildPath = function (ctx, shape) {
      var x = shape.cx;
      var y = shape.cy;
      var a = shape.width;
      var b = shape.height;
      ctx.moveTo(x, y + a);
      ctx.bezierCurveTo(x + a, y + a, x + a * 3 / 2, y - a / 3, x, y - b);
      ctx.bezierCurveTo(x - a * 3 / 2, y - a / 3, x - a, y + a, x, y + a);
      ctx.closePath();
    };

    return Droplet;
  }(Path);

  Droplet.prototype.type = 'droplet';

  var HeartShape = function () {
    function HeartShape() {
      this.cx = 0;
      this.cy = 0;
      this.width = 0;
      this.height = 0;
    }

    return HeartShape;
  }();

  var Heart = function (_super) {
    __extends(Heart, _super);

    function Heart(opts) {
      return _super.call(this, opts) || this;
    }

    Heart.prototype.getDefaultShape = function () {
      return new HeartShape();
    };

    Heart.prototype.buildPath = function (ctx, shape) {
      var x = shape.cx;
      var y = shape.cy;
      var a = shape.width;
      var b = shape.height;
      ctx.moveTo(x, y);
      ctx.bezierCurveTo(x + a / 2, y - b * 2 / 3, x + a * 2, y + b / 3, x, y + b);
      ctx.bezierCurveTo(x - a * 2, y + b / 3, x - a / 2, y - b * 2 / 3, x, y);
    };

    return Heart;
  }(Path);

  Heart.prototype.type = 'heart';
  var PI$2 = Math.PI;
  var sin = Math.sin;
  var cos = Math.cos;

  var IsogonShape = function () {
    function IsogonShape() {
      this.x = 0;
      this.y = 0;
      this.r = 0;
      this.n = 0;
    }

    return IsogonShape;
  }();

  var Isogon = function (_super) {
    __extends(Isogon, _super);

    function Isogon(opts) {
      return _super.call(this, opts) || this;
    }

    Isogon.prototype.getDefaultShape = function () {
      return new IsogonShape();
    };

    Isogon.prototype.buildPath = function (ctx, shape) {
      var n = shape.n;

      if (!n || n < 2) {
        return;
      }

      var x = shape.x;
      var y = shape.y;
      var r = shape.r;
      var dStep = 2 * PI$2 / n;
      var deg = -PI$2 / 2;
      ctx.moveTo(x + r * cos(deg), y + r * sin(deg));

      for (var i = 0, end = n - 1; i < end; i++) {
        deg += dStep;
        ctx.lineTo(x + r * cos(deg), y + r * sin(deg));
      }

      ctx.closePath();
      return;
    };

    return Isogon;
  }(Path);

  Isogon.prototype.type = 'isogon';

  var RingShape = function () {
    function RingShape() {
      this.cx = 0;
      this.cy = 0;
      this.r = 0;
      this.r0 = 0;
    }

    return RingShape;
  }();

  var Ring = function (_super) {
    __extends(Ring, _super);

    function Ring(opts) {
      return _super.call(this, opts) || this;
    }

    Ring.prototype.getDefaultShape = function () {
      return new RingShape();
    };

    Ring.prototype.buildPath = function (ctx, shape) {
      var x = shape.cx;
      var y = shape.cy;
      var PI2 = Math.PI * 2;
      ctx.moveTo(x + shape.r, y);
      ctx.arc(x, y, shape.r, 0, PI2, false);
      ctx.moveTo(x + shape.r0, y);
      ctx.arc(x, y, shape.r0, 0, PI2, true);
    };

    return Ring;
  }(Path);

  Ring.prototype.type = 'ring';
  var sin$1 = Math.sin;
  var cos$1 = Math.cos;
  var radian = Math.PI / 180;

  var RoseShape = function () {
    function RoseShape() {
      this.cx = 0;
      this.cy = 0;
      this.r = [];
      this.k = 0;
      this.n = 1;
    }

    return RoseShape;
  }();

  var Rose = function (_super) {
    __extends(Rose, _super);

    function Rose(opts) {
      return _super.call(this, opts) || this;
    }

    Rose.prototype.getDefaultStyle = function () {
      return {
        stroke: '#000',
        fill: null
      };
    };

    Rose.prototype.getDefaultShape = function () {
      return new RoseShape();
    };

    Rose.prototype.buildPath = function (ctx, shape) {
      var R = shape.r;
      var k = shape.k;
      var n = shape.n;
      var x0 = shape.cx;
      var y0 = shape.cy;
      var x;
      var y;
      var r;
      ctx.moveTo(x0, y0);

      for (var i = 0, len = R.length; i < len; i++) {
        r = R[i];

        for (var j = 0; j <= 360 * n; j++) {
          x = r * sin$1(k / n * j % 360 * radian) * cos$1(j * radian) + x0;
          y = r * sin$1(k / n * j % 360 * radian) * sin$1(j * radian) + y0;
          ctx.lineTo(x, y);
        }
      }
    };

    return Rose;
  }(Path);

  Rose.prototype.type = 'rose';

  var SectorShape = function () {
    function SectorShape() {
      this.cx = 0;
      this.cy = 0;
      this.r0 = 0;
      this.r = 0;
      this.startAngle = 0;
      this.endAngle = Math.PI * 2;
      this.clockwise = true;
    }

    return SectorShape;
  }();

  var Sector = function (_super) {
    __extends(Sector, _super);

    function Sector(opts) {
      return _super.call(this, opts) || this;
    }

    Sector.prototype.getDefaultShape = function () {
      return new SectorShape();
    };

    Sector.prototype.buildPath = function (ctx, shape) {
      var x = shape.cx;
      var y = shape.cy;
      var r0 = Math.max(shape.r0 || 0, 0);
      var r = Math.max(shape.r, 0);
      var startAngle = shape.startAngle;
      var endAngle = shape.endAngle;
      var clockwise = shape.clockwise;
      var unitX = Math.cos(startAngle);
      var unitY = Math.sin(startAngle);
      ctx.moveTo(unitX * r0 + x, unitY * r0 + y);
      ctx.lineTo(unitX * r + x, unitY * r + y);
      ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
      ctx.lineTo(Math.cos(endAngle) * r0 + x, Math.sin(endAngle) * r0 + y);

      if (r0 !== 0) {
        ctx.arc(x, y, r0, endAngle, startAngle, clockwise);
      }

      ctx.closePath();
    };

    Sector.prototype.isZeroArea = function () {
      return this.shape.startAngle === this.shape.endAngle || this.shape.r === this.shape.r0;
    };

    return Sector;
  }(Path);

  Sector.prototype.type = 'sector';
  var PI$3 = Math.PI;
  var cos$2 = Math.cos;
  var sin$2 = Math.sin;

  var StarShape = function () {
    function StarShape() {
      this.cx = 0;
      this.cy = 0;
      this.n = 3;
      this.r = 0;
    }

    return StarShape;
  }();

  var Star = function (_super) {
    __extends(Star, _super);

    function Star(opts) {
      return _super.call(this, opts) || this;
    }

    Star.prototype.getDefaultShape = function () {
      return new StarShape();
    };

    Star.prototype.buildPath = function (ctx, shape) {
      var n = shape.n;

      if (!n || n < 2) {
        return;
      }

      var x = shape.cx;
      var y = shape.cy;
      var r = shape.r;
      var r0 = shape.r0;

      if (r0 == null) {
        r0 = n > 4 ? r * cos$2(2 * PI$3 / n) / cos$2(PI$3 / n) : r / 3;
      }

      var dStep = PI$3 / n;
      var deg = -PI$3 / 2;
      var xStart = x + r * cos$2(deg);
      var yStart = y + r * sin$2(deg);
      deg += dStep;
      ctx.moveTo(xStart, yStart);

      for (var i = 0, end = n * 2 - 1, ri = void 0; i < end; i++) {
        ri = i % 2 === 0 ? r0 : r;
        ctx.lineTo(x + ri * cos$2(deg), y + ri * sin$2(deg));
        deg += dStep;
      }

      ctx.closePath();
    };

    return Star;
  }(Path);

  Star.prototype.type = 'star';
  var cos$3 = Math.cos;
  var sin$3 = Math.sin;

  var TrochoidShape = function () {
    function TrochoidShape() {
      this.cx = 0;
      this.cy = 0;
      this.r = 0;
      this.r0 = 0;
      this.d = 0;
      this.location = 'out';
    }

    return TrochoidShape;
  }();

  var Trochoid = function (_super) {
    __extends(Trochoid, _super);

    function Trochoid(opts) {
      return _super.call(this, opts) || this;
    }

    Trochoid.prototype.getDefaultStyle = function () {
      return {
        stroke: '#000',
        fill: null
      };
    };

    Trochoid.prototype.getDefaultShape = function () {
      return new TrochoidShape();
    };

    Trochoid.prototype.buildPath = function (ctx, shape) {
      var R = shape.r;
      var r = shape.r0;
      var d = shape.d;
      var offsetX = shape.cx;
      var offsetY = shape.cy;
      var delta = shape.location === 'out' ? 1 : -1;
      var x1;
      var y1;
      var x2;
      var y2;

      if (shape.location && R <= r) {
        return;
      }

      var num = 0;
      var i = 1;
      var theta;
      x1 = (R + delta * r) * cos$3(0) - delta * d * cos$3(0) + offsetX;
      y1 = (R + delta * r) * sin$3(0) - d * sin$3(0) + offsetY;
      ctx.moveTo(x1, y1);

      do {
        num++;
      } while (r * num % (R + delta * r) !== 0);

      do {
        theta = Math.PI / 180 * i;
        x2 = (R + delta * r) * cos$3(theta) - delta * d * cos$3((R / r + delta) * theta) + offsetX;
        y2 = (R + delta * r) * sin$3(theta) - d * sin$3((R / r + delta) * theta) + offsetY;
        ctx.lineTo(x2, y2);
        i++;
      } while (i <= r * num / (R + delta * r) * 360);
    };

    return Trochoid;
  }(Path);

  Trochoid.prototype.type = 'trochoid';

  var RadialGradient = function (_super) {
    __extends(RadialGradient, _super);

    function RadialGradient(x, y, r, colorStops, globalCoord) {
      var _this = _super.call(this, colorStops) || this;

      _this.x = x == null ? 0.5 : x;
      _this.y = y == null ? 0.5 : y;
      _this.r = r == null ? 0.5 : r;
      _this.type = 'radial';
      _this.global = globalCoord || false;
      return _this;
    }

    return RadialGradient;
  }(Gradient);

  var extent = [0, 0];
  var extent2 = [0, 0];
  var minTv$1 = new Point();
  var maxTv$1 = new Point();

  var OrientedBoundingRect = function () {
    function OrientedBoundingRect(rect, transform) {
      this._corners = [];
      this._axes = [];
      this._origin = [0, 0];

      for (var i = 0; i < 4; i++) {
        this._corners[i] = new Point();
      }

      for (var i = 0; i < 2; i++) {
        this._axes[i] = new Point();
      }

      if (rect) {
        this.fromBoundingRect(rect, transform);
      }
    }

    OrientedBoundingRect.prototype.fromBoundingRect = function (rect, transform) {
      var corners = this._corners;
      var axes = this._axes;
      var x = rect.x;
      var y = rect.y;
      var x2 = x + rect.width;
      var y2 = y + rect.height;
      corners[0].set(x, y);
      corners[1].set(x2, y);
      corners[2].set(x2, y2);
      corners[3].set(x, y2);

      if (transform) {
        for (var i = 0; i < 4; i++) {
          corners[i].transform(transform);
        }
      }

      Point.sub(axes[0], corners[1], corners[0]);
      Point.sub(axes[1], corners[3], corners[0]);
      axes[0].normalize();
      axes[1].normalize();

      for (var i = 0; i < 2; i++) {
        this._origin[i] = axes[i].dot(corners[0]);
      }
    };

    OrientedBoundingRect.prototype.intersect = function (other, mtv) {
      var overlapped = true;
      var noMtv = !mtv;
      minTv$1.set(Infinity, Infinity);
      maxTv$1.set(0, 0);

      if (!this._intersectCheckOneSide(this, other, minTv$1, maxTv$1, noMtv, 1)) {
        overlapped = false;

        if (noMtv) {
          return overlapped;
        }
      }

      if (!this._intersectCheckOneSide(other, this, minTv$1, maxTv$1, noMtv, -1)) {
        overlapped = false;

        if (noMtv) {
          return overlapped;
        }
      }

      if (!noMtv) {
        Point.copy(mtv, overlapped ? minTv$1 : maxTv$1);
      }

      return overlapped;
    };

    OrientedBoundingRect.prototype._intersectCheckOneSide = function (self, other, minTv, maxTv, noMtv, inverse) {
      var overlapped = true;

      for (var i = 0; i < 2; i++) {
        var axis = this._axes[i];

        this._getProjMinMaxOnAxis(i, self._corners, extent);

        this._getProjMinMaxOnAxis(i, other._corners, extent2);

        if (extent[1] < extent2[0] || extent[0] > extent2[1]) {
          overlapped = false;

          if (noMtv) {
            return overlapped;
          }

          var dist0 = Math.abs(extent2[0] - extent[1]);
          var dist1 = Math.abs(extent[0] - extent2[1]);

          if (Math.min(dist0, dist1) > maxTv.len()) {
            if (dist0 < dist1) {
              Point.scale(maxTv, axis, -dist0 * inverse);
            } else {
              Point.scale(maxTv, axis, dist1 * inverse);
            }
          }
        } else if (minTv) {
          var dist0 = Math.abs(extent2[0] - extent[1]);
          var dist1 = Math.abs(extent[0] - extent2[1]);

          if (Math.min(dist0, dist1) < minTv.len()) {
            if (dist0 < dist1) {
              Point.scale(minTv, axis, dist0 * inverse);
            } else {
              Point.scale(minTv, axis, -dist1 * inverse);
            }
          }
        }
      }

      return overlapped;
    };

    OrientedBoundingRect.prototype._getProjMinMaxOnAxis = function (dim, corners, out) {
      var axis = this._axes[dim];
      var origin = this._origin;
      var proj = corners[0].dot(axis) + origin[dim];
      var min = proj;
      var max = proj;

      for (var i = 1; i < corners.length; i++) {
        var proj_1 = corners[i].dot(axis) + origin[dim];
        min = Math.min(proj_1, min);
        max = Math.max(proj_1, max);
      }

      out[0] = min;
      out[1] = max;
    };

    return OrientedBoundingRect;
  }();
  /*!
  * ZRender, a high performance 2d drawing library.
  *
  * Copyright (c) 2013, Baidu Inc.
  * All rights reserved.
  *
  * LICENSE
  * https://github.com/ecomfe/zrender/blob/master/LICENSE.txt
  */


  var useVML = !env.canvasSupported;
  var painterCtors = {};

  function delInstance(id) {}

  function isDarkMode(backgroundColor) {
    if (!backgroundColor) {
      return false;
    }

    if (typeof backgroundColor === 'string') {
      return lum(backgroundColor, 1) < DARK_MODE_THRESHOLD;
    } else if (backgroundColor.colorStops) {
      var colorStops = backgroundColor.colorStops;
      var totalLum = 0;
      var len = colorStops.length;

      for (var i = 0; i < len; i++) {
        totalLum += lum(colorStops[i].color, 1);
      }

      totalLum /= len;
      return totalLum < DARK_MODE_THRESHOLD;
    }

    return false;
  }

  var ZRender = function () {
    function ZRender(id, dom, opts) {
      var _this = this;

      this._stillFrameAccum = 0;
      this._needsRefresh = true;
      this._needsRefreshHover = true;
      this._darkMode = false;
      opts = opts || {};
      this.dom = dom;
      this.id = id;
      var storage = new Storage();
      var rendererType = opts.renderer;

      if (useVML) {
        if (!painterCtors.vml) {
          throw new Error('You need to require \'zrender/vml/vml\' to support IE8');
        }

        rendererType = 'vml';
      } else if (!rendererType) {
        rendererType = 'canvas';
      }

      if (!painterCtors[rendererType]) {
        throw new Error("Renderer '" + rendererType + "' is not imported. Please import it first.");
      }

      var painter = new painterCtors[rendererType](dom, storage, opts, id);
      this.storage = storage;
      this.painter = painter;
      var handerProxy = !env.node && !env.worker ? new HandlerDomProxy(painter.getViewportRoot(), painter.root) : null;
      this.handler = new Handler(storage, painter, handerProxy, painter.root);
      this.animation = new Animation({
        stage: {
          update: function () {
            return _this._flush(true);
          }
        }
      });
      this.animation.start();
    }

    ZRender.prototype.add = function (el) {
      this.storage.addRoot(el);
      el.addSelfToZr(this);
      this.refresh();
    };

    ZRender.prototype.remove = function (el) {
      this.storage.delRoot(el);
      el.removeSelfFromZr(this);
      this.refresh();
    };

    ZRender.prototype.configLayer = function (zLevel, config) {
      if (this.painter.configLayer) {
        this.painter.configLayer(zLevel, config);
      }

      this.refresh();
    };

    ZRender.prototype.setBackgroundColor = function (backgroundColor) {
      if (this.painter.setBackgroundColor) {
        this.painter.setBackgroundColor(backgroundColor);
      }

      this.refresh();
      this._backgroundColor = backgroundColor;
      this._darkMode = isDarkMode(backgroundColor);
    };

    ZRender.prototype.getBackgroundColor = function () {
      return this._backgroundColor;
    };

    ZRender.prototype.setDarkMode = function (darkMode) {
      this._darkMode = darkMode;
    };

    ZRender.prototype.isDarkMode = function () {
      return this._darkMode;
    };

    ZRender.prototype.refreshImmediately = function (fromInside) {
      if (!fromInside) {
        this.animation.update();
      }

      this._needsRefresh = false;
      this.painter.refresh();
      this._needsRefresh = false;
    };

    ZRender.prototype.refresh = function () {
      this._needsRefresh = true;
      this.animation.start();
    };

    ZRender.prototype.flush = function () {
      this._flush(false);
    };

    ZRender.prototype._flush = function (fromInside) {
      var triggerRendered;

      if (this._needsRefresh) {
        triggerRendered = true;
        this.refreshImmediately(fromInside);
      }

      if (this._needsRefreshHover) {
        triggerRendered = true;
        this.refreshHoverImmediately();
      }

      if (triggerRendered) {
        this._stillFrameAccum = 0;
        this.trigger('rendered');
      } else {
        this._stillFrameAccum++;

        if (this._stillFrameAccum > 10) {
          this.animation.stop();
        }
      }
    };

    ZRender.prototype.wakeUp = function () {
      this.animation.start();
      this._stillFrameAccum = 0;
    };

    ZRender.prototype.addHover = function (el) {};

    ZRender.prototype.removeHover = function (el) {};

    ZRender.prototype.clearHover = function () {};

    ZRender.prototype.refreshHover = function () {
      this._needsRefreshHover = true;
    };

    ZRender.prototype.refreshHoverImmediately = function () {
      this._needsRefreshHover = false;

      if (this.painter.refreshHover) {
        this.painter.refreshHover();
      }
    };

    ZRender.prototype.resize = function (opts) {
      opts = opts || {};
      this.painter.resize(opts.width, opts.height);
      this.handler.resize();
    };

    ZRender.prototype.clearAnimation = function () {
      this.animation.clear();
    };

    ZRender.prototype.getWidth = function () {
      return this.painter.getWidth();
    };

    ZRender.prototype.getHeight = function () {
      return this.painter.getHeight();
    };

    ZRender.prototype.pathToImage = function (e, dpr) {
      if (this.painter.pathToImage) {
        return this.painter.pathToImage(e, dpr);
      }
    };

    ZRender.prototype.setCursorStyle = function (cursorStyle) {
      this.handler.setCursorStyle(cursorStyle);
    };

    ZRender.prototype.findHover = function (x, y) {
      return this.handler.findHover(x, y);
    };

    ZRender.prototype.on = function (eventName, eventHandler, context) {
      this.handler.on(eventName, eventHandler, context);
      return this;
    };

    ZRender.prototype.off = function (eventName, eventHandler) {
      this.handler.off(eventName, eventHandler);
    };

    ZRender.prototype.trigger = function (eventName, event) {
      this.handler.trigger(eventName, event);
    };

    ZRender.prototype.clear = function () {
      var roots = this.storage.getRoots();

      for (var i = 0; i < roots.length; i++) {
        if (roots[i] instanceof Group) {
          roots[i].removeSelfFromZr(this);
        }
      }

      this.storage.delAllRoots();
      this.painter.clear();
    };

    ZRender.prototype.dispose = function () {
      this.animation.stop();
      this.clear();
      this.storage.dispose();
      this.painter.dispose();
      this.handler.dispose();
      this.animation = this.storage = this.painter = this.handler = null;
      delInstance(this.id);
    };

    return ZRender;
  }();

  function init(dom, opts) {
    var zr = new ZRender(guid(), dom, opts);
    return zr;
  }

  function registerPainter(name, Ctor) {
    painterCtors[name] = Ctor;
  }

  var RADIAN_EPSILON = 1e-4;

  function _trim(str) {
    return str.replace(/^\s+|\s+$/g, '');
  }

  function linearMap(val, domain, range, clamp) {
    var subDomain = domain[1] - domain[0];
    var subRange = range[1] - range[0];

    if (subDomain === 0) {
      return subRange === 0 ? range[0] : (range[0] + range[1]) / 2;
    }

    if (clamp) {
      if (subDomain > 0) {
        if (val <= domain[0]) {
          return range[0];
        } else if (val >= domain[1]) {
          return range[1];
        }
      } else {
        if (val >= domain[0]) {
          return range[0];
        } else if (val <= domain[1]) {
          return range[1];
        }
      }
    } else {
      if (val === domain[0]) {
        return range[0];
      }

      if (val === domain[1]) {
        return range[1];
      }
    }

    return (val - domain[0]) / subDomain * subRange + range[0];
  }

  function parsePercent$2(percent, all) {
    switch (percent) {
      case 'center':
      case 'middle':
        percent = '50%';
        break;

      case 'left':
      case 'top':
        percent = '0%';
        break;

      case 'right':
      case 'bottom':
        percent = '100%';
        break;
    }

    if (typeof percent === 'string') {
      if (_trim(percent).match(/%$/)) {
        return parseFloat(percent) / 100 * all;
      }

      return parseFloat(percent);
    }

    return percent == null ? NaN : +percent;
  }

  function round$1(x, precision, returnStr) {
    if (precision == null) {
      precision = 10;
    }

    precision = Math.min(Math.max(0, precision), 20);
    x = (+x).toFixed(precision);
    return returnStr ? x : +x;
  }

  function getPrecisionSafe(val) {
    var str = val.toString();
    var eIndex = str.indexOf('e');

    if (eIndex > 0) {
      var precision = +str.slice(eIndex + 1);
      return precision < 0 ? -precision : 0;
    } else {
      var dotIndex = str.indexOf('.');
      return dotIndex < 0 ? 0 : str.length - 1 - dotIndex;
    }
  }

  function getPixelPrecision(dataExtent, pixelExtent) {
    var log = Math.log;
    var LN10 = Math.LN10;
    var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);
    var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10);
    var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20);
    return !isFinite(precision) ? 20 : precision;
  }

  function getPercentWithPrecision(valueList, idx, precision) {
    if (!valueList[idx]) {
      return 0;
    }

    var sum = reduce(valueList, function (acc, val) {
      return acc + (isNaN(val) ? 0 : val);
    }, 0);

    if (sum === 0) {
      return 0;
    }

    var digits = Math.pow(10, precision);
    var votesPerQuota = map(valueList, function (val) {
      return (isNaN(val) ? 0 : val) / sum * digits * 100;
    });
    var targetSeats = digits * 100;
    var seats = map(votesPerQuota, function (votes) {
      return Math.floor(votes);
    });
    var currentSum = reduce(seats, function (acc, val) {
      return acc + val;
    }, 0);
    var remainder = map(votesPerQuota, function (votes, idx) {
      return votes - seats[idx];
    });

    while (currentSum < targetSeats) {
      var max = Number.NEGATIVE_INFINITY;
      var maxId = null;

      for (var i = 0, len = remainder.length; i < len; ++i) {
        if (remainder[i] > max) {
          max = remainder[i];
          maxId = i;
        }
      }

      ++seats[maxId];
      remainder[maxId] = 0;
      ++currentSum;
    }

    return seats[idx] / digits;
  }

  function remRadian(radian) {
    var pi2 = Math.PI * 2;
    return (radian % pi2 + pi2) % pi2;
  }

  function isRadianAroundZero(val) {
    return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;
  }

  var TIME_REG = /^(?:(\d{4})(?:[-\/](\d{1,2})(?:[-\/](\d{1,2})(?:[T ](\d{1,2})(?::(\d{1,2})(?::(\d{1,2})(?:[.,](\d+))?)?)?(Z|[\+\-]\d\d:?\d\d)?)?)?)?)?$/;

  function parseDate(value) {
    if (value instanceof Date) {
      return value;
    } else if (typeof value === 'string') {
      var match = TIME_REG.exec(value);

      if (!match) {
        return new Date(NaN);
      }

      if (!match[8]) {
        return new Date(+match[1], +(match[2] || 1) - 1, +match[3] || 1, +match[4] || 0, +(match[5] || 0), +match[6] || 0, +match[7] || 0);
      } else {
        var hour = +match[4] || 0;

        if (match[8].toUpperCase() !== 'Z') {
          hour -= +match[8].slice(0, 3);
        }

        return new Date(Date.UTC(+match[1], +(match[2] || 1) - 1, +match[3] || 1, hour, +(match[5] || 0), +match[6] || 0, +match[7] || 0));
      }
    } else if (value == null) {
      return new Date(NaN);
    }

    return new Date(Math.round(value));
  }

  function quantity(val) {
    return Math.pow(10, quantityExponent(val));
  }

  function quantityExponent(val) {
    if (val === 0) {
      return 0;
    }

    var exp = Math.floor(Math.log(val) / Math.LN10);

    if (val / Math.pow(10, exp) >= 10) {
      exp++;
    }

    return exp;
  }

  function nice(val, round) {
    var exponent = quantityExponent(val);
    var exp10 = Math.pow(10, exponent);
    var f = val / exp10;
    var nf;

    if (round) {
      if (f < 1.5) {
        nf = 1;
      } else if (f < 2.5) {
        nf = 2;
      } else if (f < 4) {
        nf = 3;
      } else if (f < 7) {
        nf = 5;
      } else {
        nf = 10;
      }
    } else {
      if (f < 1) {
        nf = 1;
      } else if (f < 2) {
        nf = 2;
      } else if (f < 3) {
        nf = 3;
      } else if (f < 5) {
        nf = 5;
      } else {
        nf = 10;
      }
    }

    val = nf * exp10;
    return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;
  }

  function numericToNumber(val) {
    var valFloat = parseFloat(val);
    return valFloat == val && (valFloat !== 0 || typeof val !== 'string' || val.indexOf('x') <= 0) ? valFloat : NaN;
  }

  function isNumeric(val) {
    return !isNaN(numericToNumber(val));
  }

  var DUMMY_COMPONENT_NAME_PREFIX = 'series\0';
  var INTERNAL_COMPONENT_ID_PREFIX = '\0_ec_\0';

  function normalizeToArray(value) {
    return value instanceof Array ? value : value == null ? [] : [value];
  }

  function defaultEmphasis(opt, key, subOpts) {
    if (opt) {
      opt[key] = opt[key] || {};
      opt.emphasis = opt.emphasis || {};
      opt.emphasis[key] = opt.emphasis[key] || {};

      for (var i = 0, len = subOpts.length; i < len; i++) {
        var subOptName = subOpts[i];

        if (!opt.emphasis[key].hasOwnProperty(subOptName) && opt[key].hasOwnProperty(subOptName)) {
          opt.emphasis[key][subOptName] = opt[key][subOptName];
        }
      }
    }
  }

  var TEXT_STYLE_OPTIONS = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth', 'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY', 'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding'];

  function getDataItemValue(dataItem) {
    return isObject(dataItem) && !isArray(dataItem) && !(dataItem instanceof Date) ? dataItem.value : dataItem;
  }

  function isDataItemOption(dataItem) {
    return isObject(dataItem) && !(dataItem instanceof Array);
  }

  function mappingToExists(existings, newCmptOptions, mode) {
    var isNormalMergeMode = mode === 'normalMerge';
    var isReplaceMergeMode = mode === 'replaceMerge';
    var isReplaceAllMode = mode === 'replaceAll';
    existings = existings || [];
    newCmptOptions = (newCmptOptions || []).slice();
    var existingIdIdxMap = createHashMap();
    each(newCmptOptions, function (cmptOption, index) {
      if (!isObject(cmptOption)) {
        newCmptOptions[index] = null;
        return;
      }

      cmptOption.id == null || validateIdOrName(cmptOption.id);
      cmptOption.name == null || validateIdOrName(cmptOption.name);
    });
    var result = prepareResult(existings, existingIdIdxMap, mode);

    if (isNormalMergeMode || isReplaceMergeMode) {
      mappingById(result, existings, existingIdIdxMap, newCmptOptions);
    }

    if (isNormalMergeMode) {
      mappingByName(result, newCmptOptions);
    }

    if (isNormalMergeMode || isReplaceMergeMode) {
      mappingByIndex(result, newCmptOptions, isReplaceMergeMode);
    } else if (isReplaceAllMode) {
      mappingInReplaceAllMode(result, newCmptOptions);
    }

    makeIdAndName(result);
    return result;
  }

  function prepareResult(existings, existingIdIdxMap, mode) {
    var result = [];

    if (mode === 'replaceAll') {
      return result;
    }

    for (var index = 0; index < existings.length; index++) {
      var existing = existings[index];

      if (existing && existing.id != null) {
        existingIdIdxMap.set(existing.id, index);
      }

      result.push({
        existing: mode === 'replaceMerge' || isComponentIdInternal(existing) ? null : existing,
        newOption: null,
        keyInfo: null,
        brandNew: null
      });
    }

    return result;
  }

  function mappingById(result, existings, existingIdIdxMap, newCmptOptions) {
    each(newCmptOptions, function (cmptOption, index) {
      if (!cmptOption || cmptOption.id == null) {
        return;
      }

      var optionId = makeComparableKey(cmptOption.id);
      var existingIdx = existingIdIdxMap.get(optionId);

      if (existingIdx != null) {
        var resultItem = result[existingIdx];
        assert(!resultItem.newOption, 'Duplicated option on id "' + optionId + '".');
        resultItem.newOption = cmptOption;
        resultItem.existing = existings[existingIdx];
        newCmptOptions[index] = null;
      }
    });
  }

  function mappingByName(result, newCmptOptions) {
    each(newCmptOptions, function (cmptOption, index) {
      if (!cmptOption || cmptOption.name == null) {
        return;
      }

      for (var i = 0; i < result.length; i++) {
        var existing = result[i].existing;

        if (!result[i].newOption && existing && (existing.id == null || cmptOption.id == null) && !isComponentIdInternal(cmptOption) && !isComponentIdInternal(existing) && keyExistAndEqual('name', existing, cmptOption)) {
          result[i].newOption = cmptOption;
          newCmptOptions[index] = null;
          return;
        }
      }
    });
  }

  function mappingByIndex(result, newCmptOptions, brandNew) {
    var nextIdx = 0;
    each(newCmptOptions, function (cmptOption) {
      if (!cmptOption) {
        return;
      }

      var resultItem;

      while ((resultItem = result[nextIdx]) && (resultItem.newOption || isComponentIdInternal(resultItem.existing) || resultItem.existing && cmptOption.id != null && !keyExistAndEqual('id', cmptOption, resultItem.existing))) {
        nextIdx++;
      }

      if (resultItem) {
        resultItem.newOption = cmptOption;
        resultItem.brandNew = brandNew;
      } else {
        result.push({
          newOption: cmptOption,
          brandNew: brandNew,
          existing: null,
          keyInfo: null
        });
      }

      nextIdx++;
    });
  }

  function mappingInReplaceAllMode(result, newCmptOptions) {
    each(newCmptOptions, function (cmptOption) {
      result.push({
        newOption: cmptOption,
        brandNew: true,
        existing: null,
        keyInfo: null
      });
    });
  }

  function makeIdAndName(mapResult) {
    var idMap = createHashMap();
    each(mapResult, function (item) {
      var existing = item.existing;
      existing && idMap.set(existing.id, item);
    });
    each(mapResult, function (item) {
      var opt = item.newOption;
      assert(!opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item, 'id duplicates: ' + (opt && opt.id));
      opt && opt.id != null && idMap.set(opt.id, item);
      !item.keyInfo && (item.keyInfo = {});
    });
    each(mapResult, function (item, index) {
      var existing = item.existing;
      var opt = item.newOption;
      var keyInfo = item.keyInfo;

      if (!isObject(opt)) {
        return;
      }

      keyInfo.name = opt.name != null ? makeComparableKey(opt.name) : existing ? existing.name : DUMMY_COMPONENT_NAME_PREFIX + index;

      if (existing) {
        keyInfo.id = makeComparableKey(existing.id);
      } else if (opt.id != null) {
        keyInfo.id = makeComparableKey(opt.id);
      } else {
        var idNum = 0;

        do {
          keyInfo.id = '\0' + keyInfo.name + '\0' + idNum++;
        } while (idMap.get(keyInfo.id));
      }

      idMap.set(keyInfo.id, item);
    });
  }

  function keyExistAndEqual(attr, obj1, obj2) {
    var key1 = obj1[attr];
    var key2 = obj2[attr];
    return key1 != null && key2 != null && key1 + '' === key2 + '';
  }

  function makeComparableKey(val) {
    if (true) {
      if (val == null) {
        throw new Error();
      }
    }

    return val + '';
  }

  function validateIdOrName(idOrName) {
    if (true) {
      assert(isValidIdOrName(idOrName), '`' + idOrName + '` is invalid id or name. Must be a string.');
    }
  }

  function isValidIdOrName(idOrName) {
    return isStringSafe(idOrName) || isNumeric(idOrName);
  }

  function isNameSpecified(componentModel) {
    var name = componentModel.name;
    return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX));
  }

  function isComponentIdInternal(cmptOption) {
    return cmptOption && cmptOption.id != null && makeComparableKey(cmptOption.id).indexOf(INTERNAL_COMPONENT_ID_PREFIX) === 0;
  }

  function setComponentTypeToKeyInfo(mappingResult, mainType, componentModelCtor) {
    each(mappingResult, function (item) {
      var newOption = item.newOption;

      if (isObject(newOption)) {
        item.keyInfo.mainType = mainType;
        item.keyInfo.subType = determineSubType(mainType, newOption, item.existing, componentModelCtor);
      }
    });
  }

  function determineSubType(mainType, newCmptOption, existComponent, componentModelCtor) {
    var subType = newCmptOption.type ? newCmptOption.type : existComponent ? existComponent.subType : componentModelCtor.determineSubType(mainType, newCmptOption);
    return subType;
  }

  function queryDataIndex(data, payload) {
    if (payload.dataIndexInside != null) {
      return payload.dataIndexInside;
    } else if (payload.dataIndex != null) {
      return isArray(payload.dataIndex) ? map(payload.dataIndex, function (value) {
        return data.indexOfRawIndex(value);
      }) : data.indexOfRawIndex(payload.dataIndex);
    } else if (payload.name != null) {
      return isArray(payload.name) ? map(payload.name, function (value) {
        return data.indexOfName(value);
      }) : data.indexOfName(payload.name);
    }
  }

  function makeInner() {
    var key = '__ec_inner_' + innerUniqueIndex++;
    return function (hostObj) {
      return hostObj[key] || (hostObj[key] = {});
    };
  }

  var innerUniqueIndex = Math.round(Math.random() * 5);

  function parseFinder(ecModel, finderInput, opt) {
    var finder;

    if (isString(finderInput)) {
      var obj = {};
      obj[finderInput + 'Index'] = 0;
      finder = obj;
    } else {
      finder = finderInput;
    }

    var defaultMainType = opt ? opt.defaultMainType : null;
    var queryOptionMap = createHashMap();
    var result = {};
    each(finder, function (value, key) {
      if (key === 'dataIndex' || key === 'dataIndexInside') {
        result[key] = value;
        return;
      }

      var parsedKey = key.match(/^(\w+)(Index|Id|Name)$/) || [];
      var mainType = parsedKey[1];
      var queryType = (parsedKey[2] || '').toLowerCase();

      if (!mainType || !queryType || mainType !== defaultMainType && value == null || opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0) {
        return;
      }

      var queryOption = queryOptionMap.get(mainType) || queryOptionMap.set(mainType, {});
      queryOption[queryType] = value;
    });
    queryOptionMap.each(function (queryOption, mainType) {
      var queryResult = queryReferringComponents(ecModel, mainType, queryOption, {
        useDefault: mainType === defaultMainType,
        enableAll: true,
        enableNone: true
      });
      result[mainType + 'Models'] = queryResult.models;
      result[mainType + 'Model'] = queryResult.models[0];
    });
    return result;
  }

  var SINGLE_REFERRING = {
    useDefault: true,
    enableAll: false,
    enableNone: false
  };

  function queryReferringComponents(ecModel, mainType, userOption, opt) {
    var indexOption = userOption.index;
    var idOption = userOption.id;
    var nameOption = userOption.name;
    var result = {
      models: null,
      specified: indexOption != null || idOption != null || nameOption != null
    };

    if (!result.specified) {
      var firstCmpt = void 0;
      result.models = opt.useDefault && (firstCmpt = ecModel.getComponent(mainType)) ? [firstCmpt] : [];
      return result;
    }

    if (indexOption === 'none' || indexOption === false) {
      assert(opt.enableNone, '`"none"` or `false` is not a valid value on index option.');
      result.models = [];
      return result;
    }

    if (indexOption === 'all') {
      assert(opt.enableAll, '`"all"` is not a valid value on index option.');
      indexOption = idOption = nameOption = null;
    }

    result.models = ecModel.queryComponents({
      mainType: mainType,
      index: indexOption,
      id: idOption,
      name: nameOption
    });
    return result;
  }

  function setAttribute(dom, key, value) {
    dom.setAttribute ? dom.setAttribute(key, value) : dom[key] = value;
  }

  function getAttribute(dom, key) {
    return dom.getAttribute ? dom.getAttribute(key) : dom[key];
  }

  var TYPE_DELIMITER = '.';
  var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';
  var IS_EXTENDED_CLASS = '___EC__EXTENDED_CLASS___';

  function parseClassType(componentType) {
    var ret = {
      main: '',
      sub: ''
    };

    if (componentType) {
      var typeArr = componentType.split(TYPE_DELIMITER);
      ret.main = typeArr[0] || '';
      ret.sub = typeArr[1] || '';
    }

    return ret;
  }

  function checkClassType(componentType) {
    assert(/^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType), 'componentType "' + componentType + '" illegal');
  }

  function isExtendedClass(clz) {
    return !!(clz && clz[IS_EXTENDED_CLASS]);
  }

  function enableClassExtend(rootClz, mandatoryMethods) {
    rootClz.$constructor = rootClz;

    rootClz.extend = function (proto) {
      if (true) {
        each(mandatoryMethods, function (method) {
          if (!proto[method]) {
            console.warn('Method `' + method + '` should be implemented' + (proto.type ? ' in ' + proto.type : '') + '.');
          }
        });
      }

      var superClass = this;

      function ExtendedClass() {
        var args = [];

        for (var _i = 0; _i < arguments.length; _i++) {
          args[_i] = arguments[_i];
        }

        if (!proto.$constructor) {
          if (!isESClass(superClass)) {
            superClass.apply(this, arguments);
          } else {
            var ins = createObject(ExtendedClass.prototype, new (superClass.bind.apply(superClass, __spreadArrays([void 0], args)))());
            return ins;
          }
        } else {
          proto.$constructor.apply(this, arguments);
        }
      }

      ExtendedClass[IS_EXTENDED_CLASS] = true;
      extend(ExtendedClass.prototype, proto);
      ExtendedClass.extend = this.extend;
      ExtendedClass.superCall = superCall;
      ExtendedClass.superApply = superApply;
      inherits(ExtendedClass, this);
      ExtendedClass.superClass = superClass;
      return ExtendedClass;
    };
  }

  function isESClass(fn) {
    return typeof fn === 'function' && /^class\s/.test(Function.prototype.toString.call(fn));
  }

  function mountExtend(SubClz, SupperClz) {
    SubClz.extend = SupperClz.extend;
  }

  var classBase = Math.round(Math.random() * 10);

  function enableClassCheck(target) {
    var classAttr = ['__\0is_clz', classBase++].join('_');
    target.prototype[classAttr] = true;

    if (true) {
      assert(!target.isInstance, 'The method "is" can not be defined.');
    }

    target.isInstance = function (obj) {
      return !!(obj && obj[classAttr]);
    };
  }

  function superCall(context, methodName) {
    var args = [];

    for (var _i = 2; _i < arguments.length; _i++) {
      args[_i - 2] = arguments[_i];
    }

    return this.superClass.prototype[methodName].apply(context, args);
  }

  function superApply(context, methodName, args) {
    return this.superClass.prototype[methodName].apply(context, args);
  }

  function enableClassManagement(target, options) {
    options = options || {};
    var storage = {};

    target.registerClass = function (clz) {
      var componentFullType = clz.type || clz.prototype.type;

      if (componentFullType) {
        checkClassType(componentFullType);
        clz.prototype.type = componentFullType;
        var componentTypeInfo = parseClassType(componentFullType);

        if (!componentTypeInfo.sub) {
          if (true) {
            if (storage[componentTypeInfo.main]) {
              console.warn(componentTypeInfo.main + ' exists.');
            }
          }

          storage[componentTypeInfo.main] = clz;
        } else if (componentTypeInfo.sub !== IS_CONTAINER) {
          var container = makeContainer(componentTypeInfo);
          container[componentTypeInfo.sub] = clz;
        }
      }

      return clz;
    };

    target.getClass = function (mainType, subType, throwWhenNotFound) {
      var clz = storage[mainType];

      if (clz && clz[IS_CONTAINER]) {
        clz = subType ? clz[subType] : null;
      }

      if (throwWhenNotFound && !clz) {
        throw new Error(!subType ? mainType + '.' + 'type should be specified.' : 'Component ' + mainType + '.' + (subType || '') + ' not exists. Load it first.');
      }

      return clz;
    };

    target.getClassesByMainType = function (componentType) {
      var componentTypeInfo = parseClassType(componentType);
      var result = [];
      var obj = storage[componentTypeInfo.main];

      if (obj && obj[IS_CONTAINER]) {
        each(obj, function (o, type) {
          type !== IS_CONTAINER && result.push(o);
        });
      } else {
        result.push(obj);
      }

      return result;
    };

    target.hasClass = function (componentType) {
      var componentTypeInfo = parseClassType(componentType);
      return !!storage[componentTypeInfo.main];
    };

    target.getAllClassMainTypes = function () {
      var types = [];
      each(storage, function (obj, type) {
        types.push(type);
      });
      return types;
    };

    target.hasSubTypes = function (componentType) {
      var componentTypeInfo = parseClassType(componentType);
      var obj = storage[componentTypeInfo.main];
      return obj && obj[IS_CONTAINER];
    };

    function makeContainer(componentTypeInfo) {
      var container = storage[componentTypeInfo.main];

      if (!container || !container[IS_CONTAINER]) {
        container = storage[componentTypeInfo.main] = {};
        container[IS_CONTAINER] = true;
      }

      return container;
    }

    if (options.registerWhenExtend) {
      var originalExtend_1 = target.extend;

      if (originalExtend_1) {
        target.extend = function (proto) {
          var ExtendedClass = originalExtend_1.call(this, proto);
          return target.registerClass(ExtendedClass);
        };
      }
    }
  }

  function makeStyleMapper(properties, ignoreParent) {
    for (var i = 0; i < properties.length; i++) {
      if (!properties[i][1]) {
        properties[i][1] = properties[i][0];
      }
    }

    ignoreParent = ignoreParent || false;
    return function (model, excludes, includes) {
      var style = {};

      for (var i = 0; i < properties.length; i++) {
        var propName = properties[i][1];

        if (excludes && indexOf(excludes, propName) >= 0 || includes && indexOf(includes, propName) < 0) {
          continue;
        }

        var val = model.getShallow(propName, ignoreParent);

        if (val != null) {
          style[properties[i][0]] = val;
        }
      }

      return style;
    };
  }

  var AREA_STYLE_KEY_MAP = [['fill', 'color'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['opacity'], ['shadowColor']];
  var getAreaStyle = makeStyleMapper(AREA_STYLE_KEY_MAP);

  var AreaStyleMixin = function () {
    function AreaStyleMixin() {}

    AreaStyleMixin.prototype.getAreaStyle = function (excludes, includes) {
      return getAreaStyle(this, excludes, includes);
    };

    return AreaStyleMixin;
  }();

  var getECData = makeInner();
  var _highlightNextDigit = 1;
  var _highlightKeyMap = {};
  var getSavedStates = makeInner();
  var HOVER_STATE_NORMAL = 0;
  var HOVER_STATE_BLUR = 1;
  var HOVER_STATE_EMPHASIS = 2;
  var SPECIAL_STATES = ['emphasis', 'blur', 'select'];
  var DISPLAY_STATES = ['normal', 'emphasis', 'blur', 'select'];
  var Z2_EMPHASIS_LIFT = 10;
  var Z2_SELECT_LIFT = 9;
  var HIGHLIGHT_ACTION_TYPE = 'highlight';
  var DOWNPLAY_ACTION_TYPE = 'downplay';
  var SELECT_ACTION_TYPE = 'select';
  var UNSELECT_ACTION_TYPE = 'unselect';
  var TOGGLE_SELECT_ACTION_TYPE = 'toggleSelect';

  function hasFillOrStroke(fillOrStroke) {
    return fillOrStroke != null && fillOrStroke !== 'none';
  }

  var liftedColorCache = new LRU(100);

  function liftColor(color) {
    if (typeof color !== 'string') {
      return color;
    }

    var liftedColor = liftedColorCache.get(color);

    if (!liftedColor) {
      liftedColor = lift(color, -0.1);
      liftedColorCache.put(color, liftedColor);
    }

    return liftedColor;
  }

  function doChangeHoverState(el, stateName, hoverStateEnum) {
    if (el.onHoverStateChange) {
      if ((el.hoverState || 0) !== hoverStateEnum) {
        el.onHoverStateChange(stateName);
      }
    }

    el.hoverState = hoverStateEnum;
  }

  function singleEnterEmphasis(el) {
    doChangeHoverState(el, 'emphasis', HOVER_STATE_EMPHASIS);
  }

  function singleLeaveEmphasis(el) {
    doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
  }

  function singleEnterBlur(el) {
    doChangeHoverState(el, 'blur', HOVER_STATE_BLUR);
  }

  function singleLeaveBlur(el) {
    doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
  }

  function singleEnterSelect(el) {
    el.selected = true;
  }

  function singleLeaveSelect(el) {
    el.selected = false;
  }

  function updateElementState(el, updater, commonParam) {
    updater(el, commonParam);
  }

  function traverseUpdateState(el, updater, commonParam) {
    updateElementState(el, updater, commonParam);
    el.isGroup && el.traverse(function (child) {
      updateElementState(child, updater, commonParam);
    });
  }

  function setStatesFlag(el, stateName) {
    switch (stateName) {
      case 'emphasis':
        el.hoverState = HOVER_STATE_EMPHASIS;
        break;

      case 'normal':
        el.hoverState = HOVER_STATE_NORMAL;
        break;

      case 'blur':
        el.hoverState = HOVER_STATE_BLUR;
        break;

      case 'select':
        el.selected = true;
    }
  }

  function getFromStateStyle(el, props, toStateName, defaultValue) {
    var style = el.style;
    var fromState = {};

    for (var i = 0; i < props.length; i++) {
      var propName = props[i];
      var val = style[propName];
      fromState[propName] = val == null ? defaultValue && defaultValue[propName] : val;
    }

    for (var i = 0; i < el.animators.length; i++) {
      var animator = el.animators[i];

      if (animator.__fromStateTransition && animator.__fromStateTransition.indexOf(toStateName) < 0 && animator.targetName === 'style') {
        animator.saveFinalToTarget(fromState, props);
      }
    }

    return fromState;
  }

  function createEmphasisDefaultState(el, stateName, targetStates, state) {
    var hasSelect = targetStates && indexOf(targetStates, 'select') >= 0;
    var cloned = false;

    if (el instanceof Path) {
      var store = getSavedStates(el);
      var fromFill = hasSelect ? store.selectFill || store.normalFill : store.normalFill;
      var fromStroke = hasSelect ? store.selectStroke || store.normalStroke : store.normalStroke;

      if (hasFillOrStroke(fromFill) || hasFillOrStroke(fromStroke)) {
        state = state || {};
        var emphasisStyle = state.style || {};

        if (!hasFillOrStroke(emphasisStyle.fill) && hasFillOrStroke(fromFill)) {
          cloned = true;
          state = extend({}, state);
          emphasisStyle = extend({}, emphasisStyle);
          emphasisStyle.fill = liftColor(fromFill);
        } else if (!hasFillOrStroke(emphasisStyle.stroke) && hasFillOrStroke(fromStroke)) {
          if (!cloned) {
            state = extend({}, state);
            emphasisStyle = extend({}, emphasisStyle);
          }

          emphasisStyle.stroke = liftColor(fromStroke);
        }

        state.style = emphasisStyle;
      }
    }

    if (state) {
      if (state.z2 == null) {
        if (!cloned) {
          state = extend({}, state);
        }

        var z2EmphasisLift = el.z2EmphasisLift;
        state.z2 = el.z2 + (z2EmphasisLift != null ? z2EmphasisLift : Z2_EMPHASIS_LIFT);
      }
    }

    return state;
  }

  function createSelectDefaultState(el, stateName, state) {
    if (state) {
      if (state.z2 == null) {
        state = extend({}, state);
        var z2SelectLift = el.z2SelectLift;
        state.z2 = el.z2 + (z2SelectLift != null ? z2SelectLift : Z2_SELECT_LIFT);
      }
    }

    return state;
  }

  function createBlurDefaultState(el, stateName, state) {
    var hasBlur = indexOf(el.currentStates, stateName) >= 0;
    var currentOpacity = el.style.opacity;
    var fromState = !hasBlur ? getFromStateStyle(el, ['opacity'], stateName, {
      opacity: 1
    }) : null;
    state = state || {};
    var blurStyle = state.style || {};

    if (blurStyle.opacity == null) {
      state = extend({}, state);
      blurStyle = extend({
        opacity: hasBlur ? currentOpacity : fromState.opacity * 0.1
      }, blurStyle);
      state.style = blurStyle;
    }

    return state;
  }

  function elementStateProxy(stateName, targetStates) {
    var state = this.states[stateName];

    if (this.style) {
      if (stateName === 'emphasis') {
        return createEmphasisDefaultState(this, stateName, targetStates, state);
      } else if (stateName === 'blur') {
        return createBlurDefaultState(this, stateName, state);
      } else if (stateName === 'select') {
        return createSelectDefaultState(this, stateName, state);
      }
    }

    return state;
  }

  function setDefaultStateProxy(el) {
    el.stateProxy = elementStateProxy;
    var textContent = el.getTextContent();
    var textGuide = el.getTextGuideLine();

    if (textContent) {
      textContent.stateProxy = elementStateProxy;
    }

    if (textGuide) {
      textGuide.stateProxy = elementStateProxy;
    }
  }

  function enterEmphasisWhenMouseOver(el, e) {
    !shouldSilent(el, e) && !el.__highByOuter && traverseUpdateState(el, singleEnterEmphasis);
  }

  function leaveEmphasisWhenMouseOut(el, e) {
    !shouldSilent(el, e) && !el.__highByOuter && traverseUpdateState(el, singleLeaveEmphasis);
  }

  function enterEmphasis(el, highlightDigit) {
    el.__highByOuter |= 1 << (highlightDigit || 0);
    traverseUpdateState(el, singleEnterEmphasis);
  }

  function leaveEmphasis(el, highlightDigit) {
    !(el.__highByOuter &= ~(1 << (highlightDigit || 0))) && traverseUpdateState(el, singleLeaveEmphasis);
  }

  function enterBlur(el) {
    traverseUpdateState(el, singleEnterBlur);
  }

  function leaveBlur(el) {
    traverseUpdateState(el, singleLeaveBlur);
  }

  function enterSelect(el) {
    traverseUpdateState(el, singleEnterSelect);
  }

  function leaveSelect(el) {
    traverseUpdateState(el, singleLeaveSelect);
  }

  function shouldSilent(el, e) {
    return el.__highDownSilentOnTouch && e.zrByTouch;
  }

  function allLeaveBlur(ecIns) {
    var model = ecIns.getModel();
    model.eachComponent(function (componentType, componentModel) {
      var view = componentType === 'series' ? ecIns.getViewOfSeriesModel(componentModel) : ecIns.getViewOfComponentModel(componentModel);
      view.group.traverse(function (child) {
        singleLeaveBlur(child);
      });
    });
  }

  function toggleSeriesBlurState(targetSeriesIndex, focus, blurScope, ecIns, isBlur) {
    var ecModel = ecIns.getModel();
    blurScope = blurScope || 'coordinateSystem';

    function leaveBlurOfIndices(data, dataIndices) {
      for (var i = 0; i < dataIndices.length; i++) {
        var itemEl = data.getItemGraphicEl(dataIndices[i]);
        itemEl && leaveBlur(itemEl);
      }
    }

    if (!isBlur) {
      allLeaveBlur(ecIns);
      return;
    }

    if (targetSeriesIndex == null) {
      return;
    }

    if (!focus || focus === 'none') {
      return;
    }

    var targetSeriesModel = ecModel.getSeriesByIndex(targetSeriesIndex);
    var targetCoordSys = targetSeriesModel.coordinateSystem;

    if (targetCoordSys && targetCoordSys.master) {
      targetCoordSys = targetCoordSys.master;
    }

    var blurredSeries = [];
    ecModel.eachSeries(function (seriesModel) {
      var sameSeries = targetSeriesModel === seriesModel;
      var coordSys = seriesModel.coordinateSystem;

      if (coordSys && coordSys.master) {
        coordSys = coordSys.master;
      }

      var sameCoordSys = coordSys && targetCoordSys ? coordSys === targetCoordSys : sameSeries;

      if (!(blurScope === 'series' && !sameSeries || blurScope === 'coordinateSystem' && !sameCoordSys || focus === 'series' && sameSeries)) {
        var view = ecIns.getViewOfSeriesModel(seriesModel);
        view.group.traverse(function (child) {
          singleEnterBlur(child);
        });

        if (isArrayLike(focus)) {
          leaveBlurOfIndices(seriesModel.getData(), focus);
        } else if (isObject(focus)) {
          var dataTypes = keys(focus);

          for (var d = 0; d < dataTypes.length; d++) {
            leaveBlurOfIndices(seriesModel.getData(dataTypes[d]), focus[dataTypes[d]]);
          }
        }

        blurredSeries.push(seriesModel);
      }
    });
    ecModel.eachComponent(function (componentType, componentModel) {
      if (componentType === 'series') {
        return;
      }

      var view = ecIns.getViewOfComponentModel(componentModel);

      if (view && view.blurSeries) {
        view.blurSeries(blurredSeries, ecModel);
      }
    });
  }

  function toggleSeriesBlurStateFromPayload(seriesModel, payload, ecIns) {
    if (!isHighDownPayload(payload)) {
      return;
    }

    var isHighlight = payload.type === HIGHLIGHT_ACTION_TYPE;
    var seriesIndex = seriesModel.seriesIndex;
    var data = seriesModel.getData(payload.dataType);
    var dataIndex = queryDataIndex(data, payload);
    dataIndex = (isArray(dataIndex) ? dataIndex[0] : dataIndex) || 0;
    var el = data.getItemGraphicEl(dataIndex);

    if (!el) {
      var count = data.count();
      var current = 0;

      while (!el && current < count) {
        el = data.getItemGraphicEl(current++);
      }
    }

    if (el) {
      var ecData = getECData(el);
      toggleSeriesBlurState(seriesIndex, ecData.focus, ecData.blurScope, ecIns, isHighlight);
    } else {
      var focus_1 = seriesModel.get(['emphasis', 'focus']);
      var blurScope = seriesModel.get(['emphasis', 'blurScope']);

      if (focus_1 != null) {
        toggleSeriesBlurState(seriesIndex, focus_1, blurScope, ecIns, isHighlight);
      }
    }
  }

  function toggleSelectionFromPayload(seriesModel, payload, ecIns) {
    if (!isSelectChangePayload(payload)) {
      return;
    }

    var dataType = payload.dataType;
    var data = seriesModel.getData(dataType);
    var dataIndex = queryDataIndex(data, payload);

    if (!isArray(dataIndex)) {
      dataIndex = [dataIndex];
    }

    seriesModel[payload.type === TOGGLE_SELECT_ACTION_TYPE ? 'toggleSelect' : payload.type === SELECT_ACTION_TYPE ? 'select' : 'unselect'](dataIndex, dataType);
  }

  function updateSeriesElementSelection(seriesModel) {
    var allData = seriesModel.getAllData();
    each(allData, function (_a) {
      var data = _a.data,
          type = _a.type;
      data.eachItemGraphicEl(function (el, idx) {
        seriesModel.isSelected(idx, type) ? enterSelect(el) : leaveSelect(el);
      });
    });
  }

  function getAllSelectedIndices(ecModel) {
    var ret = [];
    ecModel.eachSeries(function (seriesModel) {
      var allData = seriesModel.getAllData();
      each(allData, function (_a) {
        var data = _a.data,
            type = _a.type;
        var dataIndices = seriesModel.getSelectedDataIndices();

        if (dataIndices.length > 0) {
          var item = {
            dataIndex: dataIndices,
            seriesIndex: seriesModel.seriesIndex
          };

          if (type != null) {
            item.dataType = type;
          }

          ret.push(item);
        }
      });
    });
    return ret;
  }

  function enableHoverEmphasis(el, focus, blurScope) {
    setAsHighDownDispatcher(el, true);
    traverseUpdateState(el, setDefaultStateProxy);
    enableHoverFocus(el, focus, blurScope);
  }

  function enableHoverFocus(el, focus, blurScope) {
    if (focus != null) {
      var ecData = getECData(el);
      ecData.focus = focus;
      ecData.blurScope = blurScope;
    }
  }

  var OTHER_STATES = ['emphasis', 'blur', 'select'];
  var styleGetterMap = {
    itemStyle: 'getItemStyle',
    lineStyle: 'getLineStyle',
    areaStyle: 'getAreaStyle'
  };

  function setStatesStylesFromModel(el, itemModel, styleType, getterType) {
    styleType = styleType || 'itemStyle';

    for (var i = 0; i < OTHER_STATES.length; i++) {
      var stateName = OTHER_STATES[i];
      var model = itemModel.getModel([stateName, styleType]);
      var state = el.ensureState(stateName);
      state.style = model[getterType || styleGetterMap[styleType]]();
    }
  }

  function setAsHighDownDispatcher(el, asDispatcher) {
    var disable = asDispatcher === false;
    var extendedEl = el;

    if (el.highDownSilentOnTouch) {
      extendedEl.__highDownSilentOnTouch = el.highDownSilentOnTouch;
    }

    if (!disable || extendedEl.__highDownDispatcher) {
      extendedEl.__highByOuter = extendedEl.__highByOuter || 0;
      extendedEl.__highDownDispatcher = !disable;
    }
  }

  function isHighDownDispatcher(el) {
    return !!(el && el.__highDownDispatcher);
  }

  function getHighlightDigit(highlightKey) {
    var highlightDigit = _highlightKeyMap[highlightKey];

    if (highlightDigit == null && _highlightNextDigit <= 32) {
      highlightDigit = _highlightKeyMap[highlightKey] = _highlightNextDigit++;
    }

    return highlightDigit;
  }

  function isSelectChangePayload(payload) {
    var payloadType = payload.type;
    return payloadType === SELECT_ACTION_TYPE || payloadType === UNSELECT_ACTION_TYPE || payloadType === TOGGLE_SELECT_ACTION_TYPE;
  }

  function isHighDownPayload(payload) {
    var payloadType = payload.type;
    return payloadType === HIGHLIGHT_ACTION_TYPE || payloadType === DOWNPLAY_ACTION_TYPE;
  }

  function savePathStates(el) {
    var store = getSavedStates(el);
    store.normalFill = el.style.fill;
    store.normalStroke = el.style.stroke;
    var selectState = el.states.select || {};
    store.selectFill = selectState.style && selectState.style.fill || null;
    store.selectStroke = selectState.style && selectState.style.stroke || null;
  }

  var ECHARTS_PREFIX = '[ECharts] ';
  var storedLogs = {};
  var hasConsole = typeof console !== 'undefined' && console.warn && console.log;

  function warn(str) {
    if (hasConsole) {
      console.warn(ECHARTS_PREFIX + str);
    }
  }

  function deprecateLog(str) {
    if (true) {
      if (storedLogs[str]) {
        return;
      }

      if (hasConsole) {
        storedLogs[str] = true;
        console.warn(ECHARTS_PREFIX + 'DEPRECATED: ' + str);
      }
    }
  }

  function deprecateReplaceLog(oldOpt, newOpt, scope) {
    if (true) {
      deprecateLog((scope ? "[" + scope + "]" : '') + (oldOpt + " is deprecated, use " + newOpt + " instead."));
    }
  }

  function consoleLog() {
    var args = [];

    for (var _i = 0; _i < arguments.length; _i++) {
      args[_i] = arguments[_i];
    }

    if (true) {
      if (typeof console !== 'undefined' && console.log) {
        console.log.apply(console, args);
      }
    }
  }

  function makePrintable() {
    var hintInfo = [];

    for (var _i = 0; _i < arguments.length; _i++) {
      hintInfo[_i] = arguments[_i];
    }

    var msg = '';

    if (true) {
      msg = map(hintInfo, function (arg) {
        if (isString(arg)) {
          return arg;
        } else if (typeof JSON !== 'undefined' && JSON.stringify) {
          try {
            return JSON.stringify(arg, function (n, val) {
              return val === void 0 ? 'undefined' : val === Infinity ? 'Infinity' : val === -Infinity ? '-Infinity' : eqNaN(val) ? 'NaN' : val instanceof Date ? 'Date(' + val.toISOString() + ')' : isFunction(val) ? 'function () { ... }' : isRegExp(val) ? val + '' : val;
            });
          } catch (err) {
            return '?';
          }
        } else {
          return '?';
        }
      }).join(' ');
    }

    return msg;
  }

  var EMPTY_OBJ = {};

  function getLabelText(opt, stateModels, overrideValue) {
    var labelFetcher = opt.labelFetcher;
    var labelDataIndex = opt.labelDataIndex;
    var labelDimIndex = opt.labelDimIndex;
    var normalModel = stateModels.normal;
    var baseText;

    if (labelFetcher) {
      baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex, normalModel && normalModel.get('formatter'), overrideValue != null ? {
        value: overrideValue
      } : null);
    }

    if (baseText == null) {
      baseText = isFunction(opt.defaultText) ? opt.defaultText(labelDataIndex, opt) : opt.defaultText;
    }

    var statesText = {
      normal: baseText
    };

    for (var i = 0; i < SPECIAL_STATES.length; i++) {
      var stateName = SPECIAL_STATES[i];
      var stateModel = stateModels[stateName];
      statesText[stateName] = retrieve2(labelFetcher ? labelFetcher.getFormattedLabel(labelDataIndex, stateName, null, labelDimIndex, stateModel && stateModel.get('formatter')) : null, baseText);
    }

    return statesText;
  }

  function setLabelStyle(targetEl, labelStatesModels, opt, stateSpecified) {
    opt = opt || EMPTY_OBJ;
    var isSetOnText = targetEl instanceof ZRText;
    var needsCreateText = false;

    for (var i = 0; i < DISPLAY_STATES.length; i++) {
      var stateModel = labelStatesModels[DISPLAY_STATES[i]];

      if (stateModel && stateModel.getShallow('show')) {
        needsCreateText = true;
        break;
      }
    }

    var textContent = isSetOnText ? targetEl : null;

    if (needsCreateText) {
      if (!isSetOnText) {
        textContent = targetEl.getTextContent();

        if (!textContent) {
          textContent = new ZRText();
          targetEl.setTextContent(textContent);
        }

        if (targetEl.stateProxy) {
          textContent.stateProxy = targetEl.stateProxy;
        }
      }

      var labelStatesTexts = getLabelText(opt, labelStatesModels);
      var normalModel = labelStatesModels.normal;
      var showNormal = normalModel.getShallow('show');
      var normalStyle = createTextStyle(normalModel, stateSpecified && stateSpecified.normal, opt, false, !isSetOnText);
      normalStyle.text = labelStatesTexts.normal;

      if (!isSetOnText) {
        targetEl.setTextConfig(createTextConfig(normalModel, opt, false));
      }

      for (var i = 0; i < SPECIAL_STATES.length; i++) {
        var stateName = SPECIAL_STATES[i];
        var stateModel = labelStatesModels[stateName];

        if (stateModel) {
          var stateObj = textContent.ensureState(stateName);
          stateObj.ignore = !retrieve2(stateModel.getShallow('show'), showNormal);
          stateObj.style = createTextStyle(stateModel, stateSpecified && stateSpecified[stateName], opt, true, !isSetOnText);
          stateObj.style.text = labelStatesTexts[stateName];

          if (!isSetOnText) {
            var targetElEmphasisState = targetEl.ensureState(stateName);
            targetElEmphasisState.textConfig = createTextConfig(stateModel, opt, true);
          }
        }
      }

      textContent.silent = !!normalModel.getShallow('silent');

      if (textContent.style.x != null) {
        normalStyle.x = textContent.style.x;
      }

      if (textContent.style.y != null) {
        normalStyle.y = textContent.style.y;
      }

      textContent.ignore = !showNormal;
      textContent.useStyle(normalStyle);
      textContent.dirty();
    } else if (textContent) {
      textContent.ignore = true;
    }

    targetEl.dirty();
  }

  function getLabelStatesModels(itemModel, labelName) {
    labelName = labelName || 'label';
    var statesModels = {
      normal: itemModel.getModel(labelName)
    };

    for (var i = 0; i < SPECIAL_STATES.length; i++) {
      var stateName = SPECIAL_STATES[i];
      statesModels[stateName] = itemModel.getModel([stateName, labelName]);
    }

    return statesModels;
  }

  function createTextStyle(textStyleModel, specifiedTextStyle, opt, isNotNormal, isAttached) {
    var textStyle = {};
    setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached);
    specifiedTextStyle && extend(textStyle, specifiedTextStyle);
    return textStyle;
  }

  function createTextConfig(textStyleModel, opt, isNotNormal) {
    opt = opt || {};
    var textConfig = {};
    var labelPosition;
    var labelRotate = textStyleModel.getShallow('rotate');
    var labelDistance = retrieve2(textStyleModel.getShallow('distance'), isNotNormal ? null : 5);
    var labelOffset = textStyleModel.getShallow('offset');
    labelPosition = textStyleModel.getShallow('position') || (isNotNormal ? null : 'inside');
    labelPosition === 'outside' && (labelPosition = opt.defaultOutsidePosition || 'top');

    if (labelPosition != null) {
      textConfig.position = labelPosition;
    }

    if (labelOffset != null) {
      textConfig.offset = labelOffset;
    }

    if (labelRotate != null) {
      labelRotate *= Math.PI / 180;
      textConfig.rotation = labelRotate;
    }

    if (labelDistance != null) {
      textConfig.distance = labelDistance;
    }

    textConfig.outsideFill = textStyleModel.get('color') === 'inherit' ? opt.inheritColor || null : 'auto';
    return textConfig;
  }

  function setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached) {
    opt = opt || EMPTY_OBJ;
    var ecModel = textStyleModel.ecModel;
    var globalTextStyle = ecModel && ecModel.option.textStyle;
    var richItemNames = getRichItemNames(textStyleModel);
    var richResult;

    if (richItemNames) {
      richResult = {};

      for (var name_1 in richItemNames) {
        if (richItemNames.hasOwnProperty(name_1)) {
          var richTextStyle = textStyleModel.getModel(['rich', name_1]);
          setTokenTextStyle(richResult[name_1] = {}, richTextStyle, globalTextStyle, opt, isNotNormal, isAttached);
        }
      }
    }

    if (richResult) {
      textStyle.rich = richResult;
    }

    var overflow = textStyleModel.get('overflow');

    if (overflow) {
      textStyle.overflow = overflow;
    }

    var margin = textStyleModel.get('minMargin');

    if (margin != null) {
      textStyle.margin = margin;
    }

    setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, true);
  }

  function getRichItemNames(textStyleModel) {
    var richItemNameMap;

    while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {
      var rich = (textStyleModel.option || EMPTY_OBJ).rich;

      if (rich) {
        richItemNameMap = richItemNameMap || {};
        var richKeys = keys(rich);

        for (var i = 0; i < richKeys.length; i++) {
          var richKey = richKeys[i];
          richItemNameMap[richKey] = 1;
        }
      }

      textStyleModel = textStyleModel.parentModel;
    }

    return richItemNameMap;
  }

  var TEXT_PROPS_WITH_GLOBAL = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'opacity', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY'];
  var TEXT_PROPS_SELF = ['align', 'lineHeight', 'width', 'height', 'tag', 'verticalAlign'];
  var TEXT_PROPS_BOX = ['padding', 'borderWidth', 'borderRadius', 'backgroundColor', 'borderColor', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'];

  function setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, isBlock) {
    globalTextStyle = !isNotNormal && globalTextStyle || EMPTY_OBJ;
    var inheritColor = opt && opt.inheritColor;
    var fillColor = textStyleModel.getShallow('color');
    var strokeColor = textStyleModel.getShallow('textBorderColor');

    if (fillColor === 'inherit' || fillColor === 'auto') {
      if (true) {
        if (fillColor === 'auto') {
          deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\'');
        }
      }

      if (inheritColor) {
        fillColor = inheritColor;
      } else {
        fillColor = null;
      }
    }

    if (strokeColor === 'inherit' || strokeColor === 'auto') {
      if (true) {
        if (strokeColor === 'auto') {
          deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\'');
        }
      }

      if (inheritColor) {
        strokeColor = inheritColor;
      } else {
        strokeColor = null;
      }
    }

    if (!isAttached) {
      fillColor = fillColor || globalTextStyle.color;
      strokeColor = strokeColor || globalTextStyle.textBorderColor;
    }

    if (fillColor != null) {
      textStyle.fill = fillColor;
    }

    if (strokeColor != null) {
      textStyle.stroke = strokeColor;
    }

    var lineWidth = retrieve2(textStyleModel.getShallow('textBorderWidth'), globalTextStyle.textBorderWidth);

    if (lineWidth != null) {
      textStyle.lineWidth = lineWidth;
    }

    if (!isNotNormal && !isAttached) {
      if (textStyle.fill == null && opt.inheritColor) {
        textStyle.fill = opt.inheritColor;
      }
    }

    for (var i = 0; i < TEXT_PROPS_WITH_GLOBAL.length; i++) {
      var key = TEXT_PROPS_WITH_GLOBAL[i];
      var val = retrieve2(textStyleModel.getShallow(key), globalTextStyle[key]);

      if (val != null) {
        textStyle[key] = val;
      }
    }

    for (var i = 0; i < TEXT_PROPS_SELF.length; i++) {
      var key = TEXT_PROPS_SELF[i];
      var val = textStyleModel.getShallow(key);

      if (val != null) {
        textStyle[key] = val;
      }
    }

    if (textStyle.verticalAlign == null) {
      var baseline = textStyleModel.getShallow('baseline');

      if (baseline != null) {
        textStyle.verticalAlign = baseline;
      }
    }

    if (!isBlock || !opt.disableBox) {
      for (var i = 0; i < TEXT_PROPS_BOX.length; i++) {
        var key = TEXT_PROPS_BOX[i];
        var val = textStyleModel.getShallow(key);

        if (val != null) {
          textStyle[key] = val;
        }
      }

      if ((textStyle.backgroundColor === 'auto' || textStyle.backgroundColor === 'inherit') && inheritColor) {
        if (true) {
          if (textStyle.backgroundColor === 'auto') {
            deprecateReplaceLog('backgroundColor: \'auto\'', 'backgroundColor: \'inherit\'');
          }
        }

        textStyle.backgroundColor = inheritColor;
      }

      if ((textStyle.borderColor === 'auto' || textStyle.borderColor === 'inherit') && inheritColor) {
        if (true) {
          if (textStyle.borderColor === 'auto') {
            deprecateReplaceLog('borderColor: \'auto\'', 'borderColor: \'inherit\'');
          }
        }

        textStyle.borderColor = inheritColor;
      }
    }
  }

  function getFont(opt, ecModel) {
    var gTextStyleModel = ecModel && ecModel.getModel('textStyle');
    return trim([opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '', opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '', (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px', opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'].join(' '));
  }

  var PATH_COLOR = ['textStyle', 'color'];
  var tmpRichText = new ZRText();

  var TextStyleMixin = function () {
    function TextStyleMixin() {}

    TextStyleMixin.prototype.getTextColor = function (isEmphasis) {
      var ecModel = this.ecModel;
      return this.getShallow('color') || (!isEmphasis && ecModel ? ecModel.get(PATH_COLOR) : null);
    };

    TextStyleMixin.prototype.getFont = function () {
      return getFont({
        fontStyle: this.getShallow('fontStyle'),
        fontWeight: this.getShallow('fontWeight'),
        fontSize: this.getShallow('fontSize'),
        fontFamily: this.getShallow('fontFamily')
      }, this.ecModel);
    };

    TextStyleMixin.prototype.getTextRect = function (text) {
      tmpRichText.useStyle({
        text: text,
        fontStyle: this.getShallow('fontStyle'),
        fontWeight: this.getShallow('fontWeight'),
        fontSize: this.getShallow('fontSize'),
        fontFamily: this.getShallow('fontFamily'),
        verticalAlign: this.getShallow('verticalAlign') || this.getShallow('baseline'),
        padding: this.getShallow('padding'),
        lineHeight: this.getShallow('lineHeight'),
        rich: this.getShallow('rich')
      });
      tmpRichText.update();
      return tmpRichText.getBoundingRect();
    };

    return TextStyleMixin;
  }();

  var LINE_STYLE_KEY_MAP = [['lineWidth', 'width'], ['stroke', 'color'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor']];
  var getLineStyle = makeStyleMapper(LINE_STYLE_KEY_MAP);

  var LineStyleMixin = function () {
    function LineStyleMixin() {}

    LineStyleMixin.prototype.getLineStyle = function (excludes) {
      var style = getLineStyle(this, excludes);
      style.lineDash = this.getLineDash(style.lineWidth);
      return style;
    };

    LineStyleMixin.prototype.getLineDash = function (lineWidth) {
      if (lineWidth == null) {
        lineWidth = 1;
      }

      var lineType = this.get('type');
      var dotSize = Math.max(lineWidth, 2);
      var dashSize = lineWidth * 4;
      return lineType === 'solid' || lineType == null ? false : lineType === 'dashed' ? [dashSize, dashSize] : [dotSize, dotSize];
    };

    return LineStyleMixin;
  }();

  var ITEM_STYLE_KEY_MAP = [['fill', 'color'], ['stroke', 'borderColor'], ['lineWidth', 'borderWidth'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor']];
  var getItemStyle = makeStyleMapper(ITEM_STYLE_KEY_MAP);

  var ItemStyleMixin = function () {
    function ItemStyleMixin() {}

    ItemStyleMixin.prototype.getItemStyle = function (excludes, includes) {
      var style = getItemStyle(this, excludes, includes);
      var lineDash = this.getBorderLineDash();
      lineDash && (style.lineDash = lineDash);
      return style;
    };

    ItemStyleMixin.prototype.getBorderLineDash = function () {
      var lineType = this.get('borderType');
      return lineType === 'solid' || lineType == null ? null : lineType === 'dashed' ? [5, 5] : [1, 1];
    };

    return ItemStyleMixin;
  }();

  var Model = function () {
    function Model(option, parentModel, ecModel) {
      this.parentModel = parentModel;
      this.ecModel = ecModel;
      this.option = option;
    }

    Model.prototype.init = function (option, parentModel, ecModel) {
      var rest = [];

      for (var _i = 3; _i < arguments.length; _i++) {
        rest[_i - 3] = arguments[_i];
      }
    };

    Model.prototype.mergeOption = function (option, ecModel) {
      merge(this.option, option, true);
    };

    Model.prototype.get = function (path, ignoreParent) {
      if (path == null) {
        return this.option;
      }

      return this._doGet(this.parsePath(path), !ignoreParent && this.parentModel);
    };

    Model.prototype.getShallow = function (key, ignoreParent) {
      var option = this.option;
      var val = option == null ? option : option[key];

      if (val == null && !ignoreParent) {
        var parentModel = this.parentModel;

        if (parentModel) {
          val = parentModel.getShallow(key);
        }
      }

      return val;
    };

    Model.prototype.getModel = function (path, parentModel) {
      var hasPath = path != null;
      var pathFinal = hasPath ? this.parsePath(path) : null;
      var obj = hasPath ? this._doGet(pathFinal) : this.option;
      parentModel = parentModel || this.parentModel && this.parentModel.getModel(this.resolveParentPath(pathFinal));
      return new Model(obj, parentModel, this.ecModel);
    };

    Model.prototype.isEmpty = function () {
      return this.option == null;
    };

    Model.prototype.restoreData = function () {};

    Model.prototype.clone = function () {
      var Ctor = this.constructor;
      return new Ctor(clone(this.option));
    };

    Model.prototype.parsePath = function (path) {
      if (typeof path === 'string') {
        return path.split('.');
      }

      return path;
    };

    Model.prototype.resolveParentPath = function (path) {
      return path;
    };

    Model.prototype.isAnimationEnabled = function () {
      if (!env.node && this.option) {
        if (this.option.animation != null) {
          return !!this.option.animation;
        } else if (this.parentModel) {
          return this.parentModel.isAnimationEnabled();
        }
      }
    };

    Model.prototype._doGet = function (pathArr, parentModel) {
      var obj = this.option;

      if (!pathArr) {
        return obj;
      }

      for (var i = 0; i < pathArr.length; i++) {
        if (!pathArr[i]) {
          continue;
        }

        obj = obj && typeof obj === 'object' ? obj[pathArr[i]] : null;

        if (obj == null) {
          break;
        }
      }

      if (obj == null && parentModel) {
        obj = parentModel._doGet(this.resolveParentPath(pathArr), parentModel.parentModel);
      }

      return obj;
    };

    return Model;
  }();

  enableClassExtend(Model);
  enableClassCheck(Model);
  mixin(Model, LineStyleMixin);
  mixin(Model, ItemStyleMixin);
  mixin(Model, AreaStyleMixin);
  mixin(Model, TextStyleMixin);
  var base = Math.round(Math.random() * 10);

  function getUID(type) {
    return [type || '', base++].join('_');
  }

  function enableSubTypeDefaulter(target) {
    var subTypeDefaulters = {};

    target.registerSubTypeDefaulter = function (componentType, defaulter) {
      var componentTypeInfo = parseClassType(componentType);
      subTypeDefaulters[componentTypeInfo.main] = defaulter;
    };

    target.determineSubType = function (componentType, option) {
      var type = option.type;

      if (!type) {
        var componentTypeMain = parseClassType(componentType).main;

        if (target.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) {
          type = subTypeDefaulters[componentTypeMain](option);
        }
      }

      return type;
    };
  }

  function enableTopologicalTravel(entity, dependencyGetter) {
    entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {
      if (!targetNameList.length) {
        return;
      }

      var result = makeDepndencyGraph(fullNameList);
      var graph = result.graph;
      var stack = result.noEntryList;
      var targetNameSet = {};
      each(targetNameList, function (name) {
        targetNameSet[name] = true;
      });

      while (stack.length) {
        var currComponentType = stack.pop();
        var currVertex = graph[currComponentType];
        var isInTargetNameSet = !!targetNameSet[currComponentType];

        if (isInTargetNameSet) {
          callback.call(context, currComponentType, currVertex.originalDeps.slice());
          delete targetNameSet[currComponentType];
        }

        each(currVertex.successor, isInTargetNameSet ? removeEdgeAndAdd : removeEdge);
      }

      each(targetNameSet, function () {
        throw new Error('Circle dependency may exists');
      });

      function removeEdge(succComponentType) {
        graph[succComponentType].entryCount--;

        if (graph[succComponentType].entryCount === 0) {
          stack.push(succComponentType);
        }
      }

      function removeEdgeAndAdd(succComponentType) {
        targetNameSet[succComponentType] = true;
        removeEdge(succComponentType);
      }
    };

    function makeDepndencyGraph(fullNameList) {
      var graph = {};
      var noEntryList = [];
      each(fullNameList, function (name) {
        var thisItem = createDependencyGraphItem(graph, name);
        var originalDeps = thisItem.originalDeps = dependencyGetter(name);
        var availableDeps = getAvailableDependencies(originalDeps, fullNameList);
        thisItem.entryCount = availableDeps.length;

        if (thisItem.entryCount === 0) {
          noEntryList.push(name);
        }

        each(availableDeps, function (dependentName) {
          if (indexOf(thisItem.predecessor, dependentName) < 0) {
            thisItem.predecessor.push(dependentName);
          }

          var thatItem = createDependencyGraphItem(graph, dependentName);

          if (indexOf(thatItem.successor, dependentName) < 0) {
            thatItem.successor.push(name);
          }
        });
      });
      return {
        graph: graph,
        noEntryList: noEntryList
      };
    }

    function createDependencyGraphItem(graph, name) {
      if (!graph[name]) {
        graph[name] = {
          predecessor: [],
          successor: []
        };
      }

      return graph[name];
    }

    function getAvailableDependencies(originalDeps, fullNameList) {
      var availableDeps = [];
      each(originalDeps, function (dep) {
        indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);
      });
      return availableDeps;
    }
  }

  function inheritDefaultOption(superOption, subOption) {
    return merge(merge({}, superOption, true), subOption, true);
  }

  var langEN = {
    time: {
      month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
      monthAbbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
      dayOfWeek: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
      dayOfWeekAbbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
    },
    legend: {
      selector: {
        all: 'All',
        inverse: 'Inv'
      }
    },
    toolbox: {
      brush: {
        title: {
          rect: 'Box Select',
          polygon: 'Lasso Select',
          lineX: 'Horizontally Select',
          lineY: 'Vertically Select',
          keep: 'Keep Selections',
          clear: 'Clear Selections'
        }
      },
      dataView: {
        title: 'Data View',
        lang: ['Data View', 'Close', 'Refresh']
      },
      dataZoom: {
        title: {
          zoom: 'Zoom',
          back: 'Zoom Reset'
        }
      },
      magicType: {
        title: {
          line: 'Switch to Line Chart',
          bar: 'Switch to Bar Chart',
          stack: 'Stack',
          tiled: 'Tile'
        }
      },
      restore: {
        title: 'Restore'
      },
      saveAsImage: {
        title: 'Save as Image',
        lang: ['Right Click to Save Image']
      }
    },
    series: {
      typeNames: {
        pie: 'Pie chart',
        bar: 'Bar chart',
        line: 'Line chart',
        scatter: 'Scatter plot',
        effectScatter: 'Ripple scatter plot',
        radar: 'Radar chart',
        tree: 'Tree',
        treemap: 'Treemap',
        boxplot: 'Boxplot',
        candlestick: 'Candlestick',
        k: 'K line chart',
        heatmap: 'Heat map',
        map: 'Map',
        parallel: 'Parallel coordinate map',
        lines: 'Line graph',
        graph: 'Relationship graph',
        sankey: 'Sankey diagram',
        funnel: 'Funnel chart',
        gauge: 'Guage',
        pictorialBar: 'Pictorial bar',
        themeRiver: 'Theme River Map',
        sunburst: 'Sunburst'
      }
    },
    aria: {
      general: {
        withTitle: 'This is a chart about "{title}"',
        withoutTitle: 'This is a chart'
      },
      series: {
        single: {
          prefix: '',
          withName: ' with type {seriesType} named {seriesName}.',
          withoutName: ' with type {seriesType}.'
        },
        multiple: {
          prefix: '. It consists of {seriesCount} series count.',
          withName: ' The {seriesId} series is a {seriesType} representing {seriesName}.',
          withoutName: ' The {seriesId} series is a {seriesType}.',
          separator: {
            middle: '',
            end: ''
          }
        }
      },
      data: {
        allData: 'The data is as follows: ',
        partialData: 'The first {displayCnt} items are: ',
        withName: 'the data for {name} is {value}',
        withoutName: '{value}',
        separator: {
          middle: ', ',
          end: '. '
        }
      }
    }
  };
  var langZH = {
    time: {
      month: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
      monthAbbr: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
      dayOfWeek: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
      dayOfWeekAbbr: ['日', '一', '二', '三', '四', '五', '六']
    },
    legend: {
      selector: {
        all: '全选',
        inverse: '反选'
      }
    },
    toolbox: {
      brush: {
        title: {
          rect: '矩形选择',
          polygon: '圈选',
          lineX: '横向选择',
          lineY: '纵向选择',
          keep: '保持选择',
          clear: '清除选择'
        }
      },
      dataView: {
        title: '数据视图',
        lang: ['数据视图', '关闭', '刷新']
      },
      dataZoom: {
        title: {
          zoom: '区域缩放',
          back: '区域缩放还原'
        }
      },
      magicType: {
        title: {
          line: '切换为折线图',
          bar: '切换为柱状图',
          stack: '切换为堆叠',
          tiled: '切换为平铺'
        }
      },
      restore: {
        title: '还原'
      },
      saveAsImage: {
        title: '保存为图片',
        lang: ['右键另存为图片']
      }
    },
    series: {
      typeNames: {
        pie: '饼图',
        bar: '柱状图',
        line: '折线图',
        scatter: '散点图',
        effectScatter: '涟漪散点图',
        radar: '雷达图',
        tree: '树图',
        treemap: '矩形树图',
        boxplot: '箱型图',
        candlestick: 'K线图',
        k: 'K线图',
        heatmap: '热力图',
        map: '地图',
        parallel: '平行坐标图',
        lines: '线图',
        graph: '关系图',
        sankey: '桑基图',
        funnel: '漏斗图',
        gauge: '仪表盘图',
        pictorialBar: '象形柱图',
        themeRiver: '主题河流图',
        sunburst: '旭日图'
      }
    },
    aria: {
      general: {
        withTitle: '这是一个关于“{title}”的图表。',
        withoutTitle: '这是一个图表，'
      },
      series: {
        single: {
          prefix: '',
          withName: '图表类型是{seriesType}，表示{seriesName}。',
          withoutName: '图表类型是{seriesType}。'
        },
        multiple: {
          prefix: '它由{seriesCount}个图表系列组成。',
          withName: '第{seriesId}个系列是一个表示{seriesName}的{seriesType}，',
          withoutName: '第{seriesId}个系列是一个{seriesType}，',
          separator: {
            middle: '；',
            end: '。'
          }
        }
      },
      data: {
        allData: '其数据是——',
        partialData: '其中，前{displayCnt}项是——',
        withName: '{name}的数据是{value}',
        withoutName: '{value}',
        separator: {
          middle: '，',
          end: ''
        }
      }
    }
  };
  var LOCALE_ZH = 'ZH';
  var LOCALE_EN = 'EN';
  var DEFAULT_LOCALE = LOCALE_EN;
  var localeStorage = {};
  var localeModels = {};
  var SYSTEM_LANG = !env.domSupported ? DEFAULT_LOCALE : function () {
    var langStr = (document.documentElement.lang || navigator.language || navigator.browserLanguage).toUpperCase();
    return langStr.indexOf(LOCALE_ZH) > -1 ? LOCALE_ZH : DEFAULT_LOCALE;
  }();

  function registerLocale(locale, localeObj) {
    locale = locale.toUpperCase();
    localeModels[locale] = new Model(localeObj);
    localeStorage[locale] = localeObj;
  }

  function createLocaleObject(locale) {
    if (isString(locale)) {
      var localeObj = localeStorage[locale.toUpperCase()] || {};

      if (locale === LOCALE_ZH || locale === LOCALE_EN) {
        return clone(localeObj);
      } else {
        return merge(clone(localeObj), clone(localeStorage[DEFAULT_LOCALE]), false);
      }
    } else {
      return merge(clone(locale), clone(localeStorage[DEFAULT_LOCALE]), false);
    }
  }

  function getLocaleModel(lang) {
    return localeModels[lang];
  }

  function getDefaultLocaleModel() {
    return localeModels[DEFAULT_LOCALE];
  }

  registerLocale(LOCALE_EN, langEN);
  registerLocale(LOCALE_ZH, langZH);
  var ONE_SECOND = 1000;
  var ONE_MINUTE = ONE_SECOND * 60;
  var ONE_HOUR = ONE_MINUTE * 60;
  var ONE_DAY = ONE_HOUR * 24;
  var ONE_YEAR = ONE_DAY * 365;
  var defaultLeveledFormatter = {
    year: '{yyyy}',
    month: '{MMM}',
    day: '{d}',
    hour: '{HH}:{mm}',
    minute: '{HH}:{mm}',
    second: '{HH}:{mm}:{ss}',
    millisecond: '{hh}:{mm}:{ss} {SSS}',
    none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss} {SSS}'
  };
  var fullDayFormatter = '{yyyy}-{MM}-{dd}';
  var fullLeveledFormatter = {
    year: '{yyyy}',
    month: '{yyyy}:{MM}',
    day: fullDayFormatter,
    hour: fullDayFormatter + ' ' + defaultLeveledFormatter.hour,
    minute: fullDayFormatter + ' ' + defaultLeveledFormatter.minute,
    second: fullDayFormatter + ' ' + defaultLeveledFormatter.second,
    millisecond: defaultLeveledFormatter.none
  };
  var primaryTimeUnits = ['year', 'month', 'day', 'hour', 'minute', 'second', 'millisecond'];
  var timeUnits = ['year', 'half-year', 'quarter', 'month', 'week', 'half-week', 'day', 'half-day', 'quarter-day', 'hour', 'minute', 'second', 'millisecond'];

  function pad(str, len) {
    str += '';
    return '0000'.substr(0, len - str.length) + str;
  }

  function getPrimaryTimeUnit(timeUnit) {
    switch (timeUnit) {
      case 'half-year':
      case 'quarter':
        return 'month';

      case 'week':
      case 'half-week':
        return 'day';

      case 'half-day':
      case 'quarter-day':
        return 'hour';

      default:
        return timeUnit;
    }
  }

  function isPrimaryTimeUnit(timeUnit) {
    return timeUnit === getPrimaryTimeUnit(timeUnit);
  }

  function getDefaultFormatPrecisionOfInterval(timeUnit) {
    switch (timeUnit) {
      case 'year':
      case 'month':
        return 'day';

      case 'millisecond':
        return 'millisecond';

      default:
        return 'second';
    }
  }

  function format(time, template, lang, isUTC) {
    var date = parseDate(time);
    var y = date[fullYearGetterName(isUTC)]();
    var M = date[monthGetterName(isUTC)]() + 1;
    var q = Math.floor((M - 1) / 4) + 1;
    var d = date[dateGetterName(isUTC)]();
    var e = date['get' + (isUTC ? 'UTC' : '') + 'Day']();
    var H = date[hoursGetterName(isUTC)]();
    var h = (H - 1) % 12 + 1;
    var m = date[minutesGetterName(isUTC)]();
    var s = date[secondsGetterName(isUTC)]();
    var S = date[millisecondsGetterName(isUTC)]();
    var localeModel = lang instanceof Model ? lang : getLocaleModel(lang || SYSTEM_LANG) || getDefaultLocaleModel();
    var timeModel = localeModel.getModel('time');
    var month = timeModel.get('month');
    var monthAbbr = timeModel.get('monthAbbr');
    var dayOfWeek = timeModel.get('dayOfWeek');
    var dayOfWeekAbbr = timeModel.get('dayOfWeekAbbr');
    return (template || '').replace(/{yyyy}/g, y + '').replace(/{yy}/g, y % 100 + '').replace(/{Q}/g, q + '').replace(/{MMMM}/g, month[M - 1]).replace(/{MMM}/g, monthAbbr[M - 1]).replace(/{MM}/g, pad(M, 2)).replace(/{M}/g, M + '').replace(/{dd}/g, pad(d, 2)).replace(/{d}/g, d + '').replace(/{eeee}/g, dayOfWeek[e]).replace(/{ee}/g, dayOfWeekAbbr[e]).replace(/{e}/g, e + '').replace(/{HH}/g, pad(H, 2)).replace(/{H}/g, H + '').replace(/{hh}/g, pad(h + '', 2)).replace(/{h}/g, h + '').replace(/{mm}/g, pad(m, 2)).replace(/{m}/g, m + '').replace(/{ss}/g, pad(s, 2)).replace(/{s}/g, s + '').replace(/{SSS}/g, pad(S, 3)).replace(/{S}/g, S + '');
  }

  function leveledFormat(tick, idx, formatter, lang, isUTC) {
    var template = null;

    if (typeof formatter === 'string') {
      template = formatter;
    } else if (typeof formatter === 'function') {
      template = formatter(tick.value, idx, {
        level: tick.level
      });
    } else {
      var defaults$1 = extend({}, defaultLeveledFormatter);

      if (tick.level > 0) {
        for (var i = 0; i < primaryTimeUnits.length; ++i) {
          defaults$1[primaryTimeUnits[i]] = "{primary|" + defaults$1[primaryTimeUnits[i]] + "}";
        }
      }

      var mergedFormatter = formatter ? formatter.inherit === false ? formatter : defaults(formatter, defaults$1) : defaults$1;
      var unit = getUnitFromValue(tick.value, isUTC);

      if (mergedFormatter[unit]) {
        template = mergedFormatter[unit];
      } else if (mergedFormatter.inherit) {
        var targetId = timeUnits.indexOf(unit);

        for (var i = targetId - 1; i >= 0; --i) {
          if (mergedFormatter[unit]) {
            template = mergedFormatter[unit];
            break;
          }
        }

        template = template || defaults$1.none;
      }

      if (isArray(template)) {
        var levelId = tick.level == null ? 0 : tick.level >= 0 ? tick.level : template.length + tick.level;
        levelId = Math.min(levelId, template.length - 1);
        template = template[levelId];
      }
    }

    return format(new Date(tick.value), template, lang, isUTC);
  }

  function getUnitFromValue(value, isUTC) {
    var date = parseDate(value);
    var M = date[monthGetterName(isUTC)]() + 1;
    var d = date[dateGetterName(isUTC)]();
    var h = date[hoursGetterName(isUTC)]();
    var m = date[minutesGetterName(isUTC)]();
    var s = date[secondsGetterName(isUTC)]();
    var S = date[millisecondsGetterName(isUTC)]();
    var isSecond = S === 0;
    var isMinute = isSecond && s === 0;
    var isHour = isMinute && m === 0;
    var isDay = isHour && h === 0;
    var isMonth = isDay && d === 1;
    var isYear = isMonth && M === 1;

    if (isYear) {
      return 'year';
    } else if (isMonth) {
      return 'month';
    } else if (isDay) {
      return 'day';
    } else if (isHour) {
      return 'hour';
    } else if (isMinute) {
      return 'minute';
    } else if (isSecond) {
      return 'second';
    } else {
      return 'millisecond';
    }
  }

  function getUnitValue(value, unit, isUTC) {
    var date = typeof value === 'number' ? parseDate(value) : value;
    unit = unit || getUnitFromValue(value, isUTC);

    switch (unit) {
      case 'year':
        return date[fullYearGetterName(isUTC)]();

      case 'half-year':
        return date[monthGetterName(isUTC)]() >= 6 ? 1 : 0;

      case 'quarter':
        return Math.floor((date[monthGetterName(isUTC)]() + 1) / 4);

      case 'month':
        return date[monthGetterName(isUTC)]();

      case 'day':
        return date[dateGetterName(isUTC)]();

      case 'half-day':
        return date[hoursGetterName(isUTC)]() / 24;

      case 'hour':
        return date[hoursGetterName(isUTC)]();

      case 'minute':
        return date[minutesGetterName(isUTC)]();

      case 'second':
        return date[secondsGetterName(isUTC)]();

      case 'millisecond':
        return date[millisecondsGetterName(isUTC)]();
    }
  }

  function fullYearGetterName(isUTC) {
    return isUTC ? 'getUTCFullYear' : 'getFullYear';
  }

  function monthGetterName(isUTC) {
    return isUTC ? 'getUTCMonth' : 'getMonth';
  }

  function dateGetterName(isUTC) {
    return isUTC ? 'getUTCDate' : 'getDate';
  }

  function hoursGetterName(isUTC) {
    return isUTC ? 'getUTCHours' : 'getHours';
  }

  function minutesGetterName(isUTC) {
    return isUTC ? 'getUTCMinutes' : 'getMinutes';
  }

  function secondsGetterName(isUTC) {
    return isUTC ? 'getUTCSeconds' : 'getSeconds';
  }

  function millisecondsGetterName(isUTC) {
    return isUTC ? 'getUTCSeconds' : 'getSeconds';
  }

  function fullYearSetterName(isUTC) {
    return isUTC ? 'setUTCFullYear' : 'setFullYear';
  }

  function monthSetterName(isUTC) {
    return isUTC ? 'setUTCMonth' : 'setMonth';
  }

  function dateSetterName(isUTC) {
    return isUTC ? 'setUTCDate' : 'setDate';
  }

  function hoursSetterName(isUTC) {
    return isUTC ? 'setUTCHours' : 'setHours';
  }

  function minutesSetterName(isUTC) {
    return isUTC ? 'setUTCMinutes' : 'setMinutes';
  }

  function secondsSetterName(isUTC) {
    return isUTC ? 'setUTCSeconds' : 'setSeconds';
  }

  function millisecondsSetterName(isUTC) {
    return isUTC ? 'setUTCSeconds' : 'setSeconds';
  }

  var innerLabel = makeInner();

  function makePath(pathData, opts, rect, layout) {
    var path = createFromString(pathData, opts);

    if (rect) {
      if (layout === 'center') {
        rect = centerGraphic(rect, path.getBoundingRect());
      }

      resizePath(path, rect);
    }

    return path;
  }

  function makeImage(imageUrl, rect, layout) {
    var zrImg = new ZRImage({
      style: {
        image: imageUrl,
        x: rect.x,
        y: rect.y,
        width: rect.width,
        height: rect.height
      },
      onload: function (img) {
        if (layout === 'center') {
          var boundingRect = {
            width: img.width,
            height: img.height
          };
          zrImg.setStyle(centerGraphic(rect, boundingRect));
        }
      }
    });
    return zrImg;
  }

  function centerGraphic(rect, boundingRect) {
    var aspect = boundingRect.width / boundingRect.height;
    var width = rect.height * aspect;
    var height;

    if (width <= rect.width) {
      height = rect.height;
    } else {
      width = rect.width;
      height = width / aspect;
    }

    var cx = rect.x + rect.width / 2;
    var cy = rect.y + rect.height / 2;
    return {
      x: cx - width / 2,
      y: cy - height / 2,
      width: width,
      height: height
    };
  }

  function resizePath(path, rect) {
    if (!path.applyTransform) {
      return;
    }

    var pathRect = path.getBoundingRect();
    var m = pathRect.calculateTransform(rect);
    path.applyTransform(m);
  }

  function animateOrSetProps(animationType, el, props, animatableModel, dataIndex, cb, during) {
    var isFrom = false;

    if (typeof dataIndex === 'function') {
      during = cb;
      cb = dataIndex;
      dataIndex = null;
    } else if (isObject(dataIndex)) {
      cb = dataIndex.cb;
      during = dataIndex.during;
      isFrom = dataIndex.isFrom;
      dataIndex = dataIndex.dataIndex;
    }

    var isUpdate = animationType === 'update';
    var isRemove = animationType === 'remove';
    var animationPayload;

    if (animatableModel && animatableModel.ecModel) {
      var updatePayload = animatableModel.ecModel.getUpdatePayload();
      animationPayload = updatePayload && updatePayload.animation;
    }

    var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();

    if (animationEnabled) {
      var duration = void 0;
      var animationEasing = void 0;
      var animationDelay = void 0;

      if (animationPayload) {
        duration = animationPayload.duration || 0;
        animationEasing = animationPayload.easing || 'cubicOut';
        animationDelay = animationPayload.delay || 0;
      } else if (isRemove) {
        duration = 200;
        animationEasing = 'cubicOut';
        animationDelay = 0;
      } else {
        duration = animatableModel.getShallow(isUpdate ? 'animationDurationUpdate' : 'animationDuration');
        animationEasing = animatableModel.getShallow(isUpdate ? 'animationEasingUpdate' : 'animationEasing');
        animationDelay = animatableModel.getShallow(isUpdate ? 'animationDelayUpdate' : 'animationDelay');

        if (typeof animationDelay === 'function') {
          animationDelay = animationDelay(dataIndex, animatableModel.getAnimationDelayParams ? animatableModel.getAnimationDelayParams(el, dataIndex) : null);
        }

        if (typeof duration === 'function') {
          duration = duration(dataIndex);
        }
      }

      if (!isRemove) {
        el.stopAnimation('remove');
      }

      duration > 0 ? isFrom ? el.animateFrom(props, {
        duration: duration,
        delay: animationDelay || 0,
        easing: animationEasing,
        done: cb,
        force: !!cb || !!during,
        scope: animationType,
        during: during
      }) : el.animateTo(props, {
        duration: duration,
        delay: animationDelay || 0,
        easing: animationEasing,
        done: cb,
        force: !!cb || !!during,
        setToFinal: true,
        scope: animationType,
        during: during
      }) : (el.stopAnimation(), el.attr(props), cb && cb());
    } else {
      el.stopAnimation();
      !isFrom && el.attr(props);
      cb && cb();
    }
  }

  function updateProps(el, props, animatableModel, dataIndex, cb, during) {
    animateOrSetProps('update', el, props, animatableModel, dataIndex, cb, during);
  }

  function initProps(el, props, animatableModel, dataIndex, cb, during) {
    animateOrSetProps('init', el, props, animatableModel, dataIndex, cb, function (percent) {
      during && during(percent);
    });
  }

  function removeElement(el, props, animatableModel, dataIndex, cb, during) {
    animateOrSetProps('remove', el, props, animatableModel, dataIndex, cb, during);
  }

  function fadeOutDisplayable(el, animatableModel, dataIndex, done) {
    el.removeTextContent();
    el.removeTextGuideLine();
    removeElement(el, {
      style: {
        opacity: 0
      }
    }, animatableModel, dataIndex, done);
  }

  function removeElementWithFadeOut(el, animatableModel, dataIndex) {
    function doRemove() {
      el.parent && el.parent.remove(el);
    }

    if (!el.isGroup) {
      fadeOutDisplayable(el, animatableModel, dataIndex, doRemove);
    } else {
      el.traverse(function (disp) {
        if (!disp.isGroup) {
          fadeOutDisplayable(disp, animatableModel, dataIndex, doRemove);
        }
      });
    }
  }

  function isElementRemoved(el) {
    if (!el.__zr) {
      return true;
    }

    for (var i = 0; i < el.animators.length; i++) {
      var animator = el.animators[i];

      if (animator.scope === 'remove') {
        return true;
      }
    }

    return false;
  }

  function animateOrSetLabel(animationType, el, data, dataIndex, labelModel, seriesModel, animatableModel, defaultTextGetter) {
    var valueAnimationEnabled = labelModel && labelModel.get('valueAnimation');

    if (valueAnimationEnabled) {
      var precisionOption = labelModel.get('precision');
      var precision_1 = !precisionOption || precisionOption === 'auto' ? 0 : precisionOption;
      var interpolateValues_1;
      var rawValues_1 = seriesModel.getRawValue(dataIndex);
      var isRawValueNumber_1 = false;

      if (typeof rawValues_1 === 'number') {
        isRawValueNumber_1 = true;
        interpolateValues_1 = rawValues_1;
      } else {
        interpolateValues_1 = [];

        for (var i = 0; i < rawValues_1.length; ++i) {
          var info = data.getDimensionInfo(i);

          if (info.type !== 'ordinal') {
            interpolateValues_1.push(rawValues_1[i]);
          }
        }
      }

      var text = el.getTextContent();
      var host_1 = text && innerLabel(text);
      host_1 && (host_1.startValue = host_1.nextValue);
      var duration = animatableModel.get('animationDuration');

      if (!duration) {
        host_1.nextValue = interpolateValues_1;
      }

      var during = function (percent) {
        var text = el.getTextContent();

        if (!text || !host_1) {
          return;
        }

        var interpolated;

        if (isRawValueNumber_1) {
          var value = interpolateNumber(host_1.startValue || 0, interpolateValues_1, percent);
          interpolated = round$1(value, precision_1);
        } else {
          interpolated = [];

          for (var i = 0; i < rawValues_1.length; ++i) {
            var info = data.getDimensionInfo(i);

            if (info.type === 'ordinal') {
              interpolated[i] = rawValues_1[i];
            } else {
              var startValues = host_1.startValue;
              var value = startValues == null ? rawValues_1[i] : interpolateNumber(startValues && startValues[i] ? startValues[i] : 0, interpolateValues_1[i], percent);
              interpolated[i] = round$1(value), precision_1;
            }
          }
        }

        host_1.nextValue = interpolated;
        var labelText = getLabelText({
          labelDataIndex: dataIndex,
          labelFetcher: seriesModel,
          defaultText: defaultTextGetter ? defaultTextGetter(interpolated) : interpolated + ''
        }, {
          normal: labelModel
        }, interpolated);
        text.style.text = labelText.normal;
        text.dirty();
      };

      var props = {};
      animateOrSetProps(animationType, el, props, animatableModel, dataIndex, null, during);
    }
  }

  function updateLabel(el, data, dataIndex, labelModel, seriesModel, animatableModel, defaultTextGetter) {
    animateOrSetLabel('update', el, data, dataIndex, labelModel, seriesModel, animatableModel, defaultTextGetter);
  }

  function initLabel(el, data, dataIndex, labelModel, seriesModel, animatableModel, defaultTextGetter) {
    animateOrSetLabel('init', el, data, dataIndex, labelModel, seriesModel, animatableModel, defaultTextGetter);
  }

  function isNotGroup(el) {
    return !el.isGroup;
  }

  function isPath(el) {
    return el.shape != null;
  }

  function groupTransition(g1, g2, animatableModel) {
    if (!g1 || !g2) {
      return;
    }

    function getElMap(g) {
      var elMap = {};
      g.traverse(function (el) {
        if (isNotGroup(el) && el.anid) {
          elMap[el.anid] = el;
        }
      });
      return elMap;
    }

    function getAnimatableProps(el) {
      var obj = {
        x: el.x,
        y: el.y,
        rotation: el.rotation
      };

      if (isPath(el)) {
        obj.shape = extend({}, el.shape);
      }

      return obj;
    }

    var elMap1 = getElMap(g1);
    g2.traverse(function (el) {
      if (isNotGroup(el) && el.anid) {
        var oldEl = elMap1[el.anid];

        if (oldEl) {
          var newProp = getAnimatableProps(el);
          el.attr(getAnimatableProps(oldEl));
          updateProps(el, newProp, animatableModel, getECData(el).dataIndex);
        }
      }
    });
  }

  function addCommas(x) {
    if (isNaN(x)) {
      return '-';
    }

    var parts = (x + '').split('.');
    return parts[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, '$1,') + (parts.length > 1 ? '.' + parts[1] : '');
  }

  var normalizeCssArray$1 = normalizeCssArray;
  var replaceReg = /([&<>"'])/g;
  var replaceMap = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    '\'': '&#39;'
  };

  function encodeHTML(source) {
    return source == null ? '' : (source + '').replace(replaceReg, function (str, c) {
      return replaceMap[c];
    });
  }

  var TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

  var wrapVar = function (varName, seriesIdx) {
    return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';
  };

  function formatTpl(tpl, paramsList, encode) {
    if (!isArray(paramsList)) {
      paramsList = [paramsList];
    }

    var seriesLen = paramsList.length;

    if (!seriesLen) {
      return '';
    }

    var isTimeAxis = paramsList[0].axisType && paramsList[0].axisType.indexOf('time') >= 0;

    if (isTimeAxis) {
      var axisValue = paramsList[0].data[paramsList[0].axisIndex];
      var date = parseDate(axisValue);
      return format(date, tpl);
    } else {
      var $vars = paramsList[0].$vars || [];

      for (var i = 0; i < $vars.length; i++) {
        var alias = TPL_VAR_ALIAS[i];
        tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0));
      }

      for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {
        for (var k = 0; k < $vars.length; k++) {
          var val = paramsList[seriesIdx][$vars[k]];
          tpl = tpl.replace(wrapVar(TPL_VAR_ALIAS[k], seriesIdx), encode ? encodeHTML(val) : val);
        }
      }
    }

    return tpl;
  }

  function getTooltipMarker(inOpt, extraCssText) {
    var opt = isString(inOpt) ? {
      color: inOpt,
      extraCssText: extraCssText
    } : inOpt || {};
    var color = opt.color;
    var type = opt.type;
    extraCssText = opt.extraCssText;
    var renderMode = opt.renderMode || 'html';
    var markerId = opt.markerId || 'X';

    if (!color) {
      return '';
    }

    if (renderMode === 'html') {
      return type === 'subItem' ? '<span style="display:inline-block;vertical-align:middle;margin-right:8px;margin-left:3px;' + 'border-radius:4px;width:4px;height:4px;background-color:' + encodeHTML(color) + ';' + (extraCssText || '') + '"></span>' : '<span style="display:inline-block;margin-right:4px;' + 'border-radius:10px;width:10px;height:10px;background-color:' + encodeHTML(color) + ';' + (extraCssText || '') + '"></span>';
    } else {
      return {
        renderMode: renderMode,
        content: '{marker' + markerId + '|}  ',
        style: {
          color: color
        }
      };
    }
  }

  function formatTime(tpl, value, isUTC) {
    if (tpl === 'week' || tpl === 'month' || tpl === 'quarter' || tpl === 'half-year' || tpl === 'year') {
      tpl = 'MM-dd\nyyyy';
    }

    var date = parseDate(value);
    var utc = isUTC ? 'UTC' : '';
    var y = date['get' + utc + 'FullYear']();
    var M = date['get' + utc + 'Month']() + 1;
    var d = date['get' + utc + 'Date']();
    var h = date['get' + utc + 'Hours']();
    var m = date['get' + utc + 'Minutes']();
    var s = date['get' + utc + 'Seconds']();
    var S = date['get' + utc + 'Milliseconds']();
    tpl = tpl.replace('MM', pad(M, 2)).replace('M', M).replace('yyyy', y).replace('yy', y % 100 + '').replace('dd', pad(d, 2)).replace('d', d).replace('hh', pad(h, 2)).replace('h', h).replace('mm', pad(m, 2)).replace('m', m).replace('ss', pad(s, 2)).replace('s', s).replace('SSS', pad(S, 3));
    return tpl;
  }

  var each$1 = each;
  var LOCATION_PARAMS = ['left', 'right', 'top', 'bottom', 'width', 'height'];
  var HV_NAMES = [['width', 'left', 'right'], ['height', 'top', 'bottom']];

  function boxLayout(orient, group, gap, maxWidth, maxHeight) {
    var x = 0;
    var y = 0;

    if (maxWidth == null) {
      maxWidth = Infinity;
    }

    if (maxHeight == null) {
      maxHeight = Infinity;
    }

    var currentLineMaxSize = 0;
    group.eachChild(function (child, idx) {
      var rect = child.getBoundingRect();
      var nextChild = group.childAt(idx + 1);
      var nextChildRect = nextChild && nextChild.getBoundingRect();
      var nextX;
      var nextY;

      if (orient === 'horizontal') {
        var moveX = rect.width + (nextChildRect ? -nextChildRect.x + rect.x : 0);
        nextX = x + moveX;

        if (nextX > maxWidth || child.newline) {
          x = 0;
          nextX = moveX;
          y += currentLineMaxSize + gap;
          currentLineMaxSize = rect.height;
        } else {
          currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);
        }
      } else {
        var moveY = rect.height + (nextChildRect ? -nextChildRect.y + rect.y : 0);
        nextY = y + moveY;

        if (nextY > maxHeight || child.newline) {
          x += currentLineMaxSize + gap;
          y = 0;
          nextY = moveY;
          currentLineMaxSize = rect.width;
        } else {
          currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);
        }
      }

      if (child.newline) {
        return;
      }

      child.x = x;
      child.y = y;
      child.markRedraw();
      orient === 'horizontal' ? x = nextX + gap : y = nextY + gap;
    });
  }

  var vbox = curry(boxLayout, 'vertical');
  var hbox = curry(boxLayout, 'horizontal');

  function getLayoutRect(positionInfo, containerRect, margin) {
    margin = normalizeCssArray$1(margin || 0);
    var containerWidth = containerRect.width;
    var containerHeight = containerRect.height;
    var left = parsePercent$2(positionInfo.left, containerWidth);
    var top = parsePercent$2(positionInfo.top, containerHeight);
    var right = parsePercent$2(positionInfo.right, containerWidth);
    var bottom = parsePercent$2(positionInfo.bottom, containerHeight);
    var width = parsePercent$2(positionInfo.width, containerWidth);
    var height = parsePercent$2(positionInfo.height, containerHeight);
    var verticalMargin = margin[2] + margin[0];
    var horizontalMargin = margin[1] + margin[3];
    var aspect = positionInfo.aspect;

    if (isNaN(width)) {
      width = containerWidth - right - horizontalMargin - left;
    }

    if (isNaN(height)) {
      height = containerHeight - bottom - verticalMargin - top;
    }

    if (aspect != null) {
      if (isNaN(width) && isNaN(height)) {
        if (aspect > containerWidth / containerHeight) {
          width = containerWidth * 0.8;
        } else {
          height = containerHeight * 0.8;
        }
      }

      if (isNaN(width)) {
        width = aspect * height;
      }

      if (isNaN(height)) {
        height = width / aspect;
      }
    }

    if (isNaN(left)) {
      left = containerWidth - right - width - horizontalMargin;
    }

    if (isNaN(top)) {
      top = containerHeight - bottom - height - verticalMargin;
    }

    switch (positionInfo.left || positionInfo.right) {
      case 'center':
        left = containerWidth / 2 - width / 2 - margin[3];
        break;

      case 'right':
        left = containerWidth - width - horizontalMargin;
        break;
    }

    switch (positionInfo.top || positionInfo.bottom) {
      case 'middle':
      case 'center':
        top = containerHeight / 2 - height / 2 - margin[0];
        break;

      case 'bottom':
        top = containerHeight - height - verticalMargin;
        break;
    }

    left = left || 0;
    top = top || 0;

    if (isNaN(width)) {
      width = containerWidth - horizontalMargin - left - (right || 0);
    }

    if (isNaN(height)) {
      height = containerHeight - verticalMargin - top - (bottom || 0);
    }

    var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);
    rect.margin = margin;
    return rect;
  }

  function fetchLayoutMode(ins) {
    var layoutMode = ins.layoutMode || ins.constructor.layoutMode;
    return isObject(layoutMode) ? layoutMode : layoutMode ? {
      type: layoutMode
    } : null;
  }

  function mergeLayoutParam(targetOption, newOption, opt) {
    var ignoreSize = opt && opt.ignoreSize;
    !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);
    var hResult = merge(HV_NAMES[0], 0);
    var vResult = merge(HV_NAMES[1], 1);
    copy(HV_NAMES[0], targetOption, hResult);
    copy(HV_NAMES[1], targetOption, vResult);

    function merge(names, hvIdx) {
      var newParams = {};
      var newValueCount = 0;
      var merged = {};
      var mergedValueCount = 0;
      var enoughParamNumber = 2;
      each$1(names, function (name) {
        merged[name] = targetOption[name];
      });
      each$1(names, function (name) {
        hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);
        hasValue(newParams, name) && newValueCount++;
        hasValue(merged, name) && mergedValueCount++;
      });

      if (ignoreSize[hvIdx]) {
        if (hasValue(newOption, names[1])) {
          merged[names[2]] = null;
        } else if (hasValue(newOption, names[2])) {
          merged[names[1]] = null;
        }

        return merged;
      }

      if (mergedValueCount === enoughParamNumber || !newValueCount) {
        return merged;
      } else if (newValueCount >= enoughParamNumber) {
        return newParams;
      } else {
        for (var i = 0; i < names.length; i++) {
          var name_1 = names[i];

          if (!hasProp(newParams, name_1) && hasProp(targetOption, name_1)) {
            newParams[name_1] = targetOption[name_1];
            break;
          }
        }

        return newParams;
      }
    }

    function hasProp(obj, name) {
      return obj.hasOwnProperty(name);
    }

    function hasValue(obj, name) {
      return obj[name] != null && obj[name] !== 'auto';
    }

    function copy(names, target, source) {
      each$1(names, function (name) {
        target[name] = source[name];
      });
    }
  }

  function getLayoutParams(source) {
    return copyLayoutParams({}, source);
  }

  function copyLayoutParams(target, source) {
    source && target && each$1(LOCATION_PARAMS, function (name) {
      source.hasOwnProperty(name) && (target[name] = source[name]);
    });
    return target;
  }

  var inner = makeInner();

  var ComponentModel = function (_super) {
    __extends(ComponentModel, _super);

    function ComponentModel(option, parentModel, ecModel) {
      var _this = _super.call(this, option, parentModel, ecModel) || this;

      _this.uid = getUID('ec_cpt_model');
      return _this;
    }

    ComponentModel.prototype.init = function (option, parentModel, ecModel) {
      this.mergeDefaultAndTheme(option, ecModel);
    };

    ComponentModel.prototype.mergeDefaultAndTheme = function (option, ecModel) {
      var layoutMode = fetchLayoutMode(this);
      var inputPositionParams = layoutMode ? getLayoutParams(option) : {};
      var themeModel = ecModel.getTheme();
      merge(option, themeModel.get(this.mainType));
      merge(option, this.getDefaultOption());

      if (layoutMode) {
        mergeLayoutParam(option, inputPositionParams, layoutMode);
      }
    };

    ComponentModel.prototype.mergeOption = function (option, ecModel) {
      merge(this.option, option, true);
      var layoutMode = fetchLayoutMode(this);

      if (layoutMode) {
        mergeLayoutParam(this.option, option, layoutMode);
      }
    };

    ComponentModel.prototype.optionUpdated = function (newCptOption, isInit) {};

    ComponentModel.prototype.getDefaultOption = function () {
      var ctor = this.constructor;

      if (!isExtendedClass(ctor)) {
        return ctor.defaultOption;
      }

      var fields = inner(this);

      if (!fields.defaultOption) {
        var optList = [];
        var clz = ctor;

        while (clz) {
          var opt = clz.prototype.defaultOption;
          opt && optList.push(opt);
          clz = clz.superClass;
        }

        var defaultOption = {};

        for (var i = optList.length - 1; i >= 0; i--) {
          defaultOption = merge(defaultOption, optList[i], true);
        }

        fields.defaultOption = defaultOption;
      }

      return fields.defaultOption;
    };

    ComponentModel.prototype.getReferringComponents = function (mainType, opt) {
      var indexKey = mainType + 'Index';
      var idKey = mainType + 'Id';
      return queryReferringComponents(this.ecModel, mainType, {
        index: this.get(indexKey, true),
        id: this.get(idKey, true)
      }, opt);
    };

    ComponentModel.prototype.getBoxLayoutParams = function () {
      var boxLayoutModel = this;
      return {
        left: boxLayoutModel.get('left'),
        top: boxLayoutModel.get('top'),
        right: boxLayoutModel.get('right'),
        bottom: boxLayoutModel.get('bottom'),
        width: boxLayoutModel.get('width'),
        height: boxLayoutModel.get('height')
      };
    };

    ComponentModel.protoInitialize = function () {
      var proto = ComponentModel.prototype;
      proto.type = 'component';
      proto.id = '';
      proto.name = '';
      proto.mainType = '';
      proto.subType = '';
      proto.componentIndex = 0;
    }();

    return ComponentModel;
  }(Model);

  mountExtend(ComponentModel, Model);
  enableClassManagement(ComponentModel, {
    registerWhenExtend: true
  });
  enableSubTypeDefaulter(ComponentModel);
  enableTopologicalTravel(ComponentModel, getDependencies);

  function getDependencies(componentType) {
    var deps = [];
    each(ComponentModel.getClassesByMainType(componentType), function (clz) {
      deps = deps.concat(clz.dependencies || clz.prototype.dependencies || []);
    });
    deps = map(deps, function (type) {
      return parseClassType(type).main;
    });

    if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) {
      deps.unshift('dataset');
    }

    return deps;
  }

  var platform = '';

  if (typeof navigator !== 'undefined') {
    platform = navigator.platform || '';
  }

  var globalDefault = {
    darkMode: 'auto',
    color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
    gradientColor: ['#f6efa6', '#d88273', '#bf444c'],
    textStyle: {
      fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif',
      fontSize: 12,
      fontStyle: 'normal',
      fontWeight: 'normal'
    },
    blendMode: null,
    stateAnimation: {
      duration: 300,
      easing: 'cubicOut'
    },
    animation: 'auto',
    animationDuration: 1000,
    animationDurationUpdate: 500,
    animationEasing: 'cubicInOut',
    animationEasingUpdate: 'cubicInOut',
    animationThreshold: 2000,
    progressiveThreshold: 3000,
    progressive: 400,
    hoverLayerThreshold: 3000,
    useUTC: false
  };
  var inner$1 = makeInner();

  function getNearestColorPalette(colors, requestColorNum) {
    var paletteNum = colors.length;

    for (var i = 0; i < paletteNum; i++) {
      if (colors[i].length > requestColorNum) {
        return colors[i];
      }
    }

    return colors[paletteNum - 1];
  }

  var ColorPaletteMixin = function () {
    function ColorPaletteMixin() {}

    ColorPaletteMixin.prototype.clearColorPalette = function () {
      inner$1(this).colorIdx = 0;
      inner$1(this).colorNameMap = {};
    };

    ColorPaletteMixin.prototype.getColorFromPalette = function (name, scope, requestColorNum) {
      scope = scope || this;
      var scopeFields = inner$1(scope);
      var colorIdx = scopeFields.colorIdx || 0;
      var colorNameMap = scopeFields.colorNameMap = scopeFields.colorNameMap || {};

      if (colorNameMap.hasOwnProperty(name)) {
        return colorNameMap[name];
      }

      var defaultColorPalette = normalizeToArray(this.get('color', true));
      var layeredColorPalette = this.get('colorLayer', true);
      var colorPalette = requestColorNum == null || !layeredColorPalette ? defaultColorPalette : getNearestColorPalette(layeredColorPalette, requestColorNum);
      colorPalette = colorPalette || defaultColorPalette;

      if (!colorPalette || !colorPalette.length) {
        return;
      }

      var color = colorPalette[colorIdx];

      if (name) {
        colorNameMap[name] = color;
      }

      scopeFields.colorIdx = (colorIdx + 1) % colorPalette.length;
      return color;
    };

    return ColorPaletteMixin;
  }();

  var VISUAL_DIMENSIONS = createHashMap(['tooltip', 'label', 'itemName', 'itemId', 'seriesName']);
  var SOURCE_FORMAT_ORIGINAL = 'original';
  var SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows';
  var SOURCE_FORMAT_OBJECT_ROWS = 'objectRows';
  var SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns';
  var SOURCE_FORMAT_TYPED_ARRAY = 'typedArray';
  var SOURCE_FORMAT_UNKNOWN = 'unknown';
  var SERIES_LAYOUT_BY_COLUMN = 'column';
  var SERIES_LAYOUT_BY_ROW = 'row';

  var Source = function () {
    function Source(fields) {
      this.data = fields.data || (fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []);
      this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN;
      this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;
      this.startIndex = fields.startIndex || 0;
      this.dimensionsDefine = fields.dimensionsDefine;
      this.dimensionsDetectCount = fields.dimensionsDetectCount;
      this.encodeDefine = fields.encodeDefine;
      this.metaRawOption = fields.metaRawOption;
    }

    Source.seriesDataToSource = function (data) {
      return new Source({
        data: data,
        sourceFormat: isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL
      });
    };

    return Source;
  }();

  var BE_ORDINAL = {
    Must: 1,
    Might: 2,
    Not: 3
  };
  var innerGlobalModel = makeInner();

  function detectSourceFormat(data) {
    var sourceFormat = SOURCE_FORMAT_UNKNOWN;

    if (isTypedArray(data)) {
      sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;
    } else if (isArray(data)) {
      if (data.length === 0) {
        sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;
      }

      for (var i = 0, len = data.length; i < len; i++) {
        var item = data[i];

        if (item == null) {
          continue;
        } else if (isArray(item)) {
          sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;
          break;
        } else if (isObject(item)) {
          sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;
          break;
        }
      }
    } else if (isObject(data)) {
      for (var key in data) {
        if (hasOwn(data, key) && isArrayLike(data[key])) {
          sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;
          break;
        }
      }
    } else if (data != null) {
      throw new Error('Invalid data');
    }

    return sourceFormat;
  }

  function resetSourceDefaulter(ecModel) {
    innerGlobalModel(ecModel).datasetMap = createHashMap();
  }

  function createSource(sourceData, thisMetaRawOption, sourceFormat, encodeDefine) {
    sourceFormat = sourceFormat || detectSourceFormat(sourceData);
    var dimInfo = determineSourceDimensions(sourceData, sourceFormat, thisMetaRawOption.seriesLayoutBy, thisMetaRawOption.sourceHeader, thisMetaRawOption.dimensions);
    var source = new Source({
      data: sourceData,
      sourceFormat: sourceFormat,
      seriesLayoutBy: thisMetaRawOption.seriesLayoutBy,
      dimensionsDefine: dimInfo.dimensionsDefine,
      startIndex: dimInfo.startIndex,
      dimensionsDetectCount: dimInfo.dimensionsDetectCount,
      encodeDefine: makeEncodeDefine(encodeDefine),
      metaRawOption: clone(thisMetaRawOption)
    });
    return source;
  }

  function inheritSourceMetaRawOption(opt) {
    return defaults(opt.thisNew, opt.parent);
  }

  function cloneSourceShallow(source) {
    return new Source({
      data: source.data,
      sourceFormat: source.sourceFormat,
      seriesLayoutBy: source.seriesLayoutBy,
      dimensionsDefine: clone(source.dimensionsDefine),
      startIndex: source.startIndex,
      dimensionsDetectCount: source.dimensionsDetectCount,
      encodeDefine: makeEncodeDefine(source.encodeDefine)
    });
  }

  function makeEncodeDefine(encodeDefine) {
    return encodeDefine ? createHashMap(encodeDefine) : null;
  }

  function determineSourceDimensions(data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine) {
    var dimensionsDetectCount;
    var startIndex;

    if (!data) {
      return {
        dimensionsDefine: normalizeDimensionsOption(dimensionsDefine),
        startIndex: startIndex,
        dimensionsDetectCount: dimensionsDetectCount
      };
    }

    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
      var dataArrayRows = data;

      if (sourceHeader === 'auto' || sourceHeader == null) {
        arrayRowsTravelFirst(function (val) {
          if (val != null && val !== '-') {
            if (isString(val)) {
              startIndex == null && (startIndex = 1);
            } else {
              startIndex = 0;
            }
          }
        }, seriesLayoutBy, dataArrayRows, 10);
      } else {
        startIndex = isNumber(sourceHeader) ? sourceHeader : sourceHeader ? 1 : 0;
      }

      if (!dimensionsDefine && startIndex === 1) {
        dimensionsDefine = [];
        arrayRowsTravelFirst(function (val, index) {
          dimensionsDefine[index] = val != null ? val + '' : '';
        }, seriesLayoutBy, dataArrayRows, Infinity);
      }

      dimensionsDetectCount = dimensionsDefine ? dimensionsDefine.length : seriesLayoutBy === SERIES_LAYOUT_BY_ROW ? dataArrayRows.length : dataArrayRows[0] ? dataArrayRows[0].length : null;
    } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
      if (!dimensionsDefine) {
        dimensionsDefine = objectRowsCollectDimensions(data);
      }
    } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
      if (!dimensionsDefine) {
        dimensionsDefine = [];
        each(data, function (colArr, key) {
          dimensionsDefine.push(key);
        });
      }
    } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {
      var value0 = getDataItemValue(data[0]);
      dimensionsDetectCount = isArray(value0) && value0.length || 1;
    } else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {
      if (true) {
        assert(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');
      }
    }

    return {
      startIndex: startIndex,
      dimensionsDefine: normalizeDimensionsOption(dimensionsDefine),
      dimensionsDetectCount: dimensionsDetectCount
    };
  }

  function normalizeDimensionsOption(dimensionsDefine) {
    if (!dimensionsDefine) {
      return;
    }

    var nameMap = createHashMap();
    return map(dimensionsDefine, function (item, index) {
      item = extend({}, isObject(item) ? item : {
        name: item
      });

      if (item.name == null) {
        return item;
      }

      item.name += '';

      if (item.displayName == null) {
        item.displayName = item.name;
      }

      var exist = nameMap.get(item.name);

      if (!exist) {
        nameMap.set(item.name, {
          count: 1
        });
      } else {
        item.name += '-' + exist.count++;
      }

      return item;
    });
  }

  function arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {
    if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {
      for (var i = 0; i < data.length && i < maxLoop; i++) {
        cb(data[i] ? data[i][0] : null, i);
      }
    } else {
      var value0 = data[0] || [];

      for (var i = 0; i < value0.length && i < maxLoop; i++) {
        cb(value0[i], i);
      }
    }
  }

  function objectRowsCollectDimensions(data) {
    var firstIndex = 0;
    var obj;

    while (firstIndex < data.length && !(obj = data[firstIndex++])) {}

    if (obj) {
      var dimensions_1 = [];
      each(obj, function (value, key) {
        dimensions_1.push(key);
      });
      return dimensions_1;
    }
  }

  function makeSeriesEncodeForAxisCoordSys(coordDimensions, seriesModel, source) {
    var encode = {};
    var datasetModel = querySeriesUpstreamDatasetModel(seriesModel);

    if (!datasetModel || !coordDimensions) {
      return encode;
    }

    var encodeItemName = [];
    var encodeSeriesName = [];
    var ecModel = seriesModel.ecModel;
    var datasetMap = innerGlobalModel(ecModel).datasetMap;
    var key = datasetModel.uid + '_' + source.seriesLayoutBy;
    var baseCategoryDimIndex;
    var categoryWayValueDimStart;
    coordDimensions = coordDimensions.slice();
    each(coordDimensions, function (coordDimInfoLoose, coordDimIdx) {
      var coordDimInfo = isObject(coordDimInfoLoose) ? coordDimInfoLoose : coordDimensions[coordDimIdx] = {
        name: coordDimInfoLoose
      };

      if (coordDimInfo.type === 'ordinal' && baseCategoryDimIndex == null) {
        baseCategoryDimIndex = coordDimIdx;
        categoryWayValueDimStart = getDataDimCountOnCoordDim(coordDimInfo);
      }

      encode[coordDimInfo.name] = [];
    });
    var datasetRecord = datasetMap.get(key) || datasetMap.set(key, {
      categoryWayDim: categoryWayValueDimStart,
      valueWayDim: 0
    });
    each(coordDimensions, function (coordDimInfo, coordDimIdx) {
      var coordDimName = coordDimInfo.name;
      var count = getDataDimCountOnCoordDim(coordDimInfo);

      if (baseCategoryDimIndex == null) {
        var start = datasetRecord.valueWayDim;
        pushDim(encode[coordDimName], start, count);
        pushDim(encodeSeriesName, start, count);
        datasetRecord.valueWayDim += count;
      } else if (baseCategoryDimIndex === coordDimIdx) {
        pushDim(encode[coordDimName], 0, count);
        pushDim(encodeItemName, 0, count);
      } else {
        var start = datasetRecord.categoryWayDim;
        pushDim(encode[coordDimName], start, count);
        pushDim(encodeSeriesName, start, count);
        datasetRecord.categoryWayDim += count;
      }
    });

    function pushDim(dimIdxArr, idxFrom, idxCount) {
      for (var i = 0; i < idxCount; i++) {
        dimIdxArr.push(idxFrom + i);
      }
    }

    function getDataDimCountOnCoordDim(coordDimInfo) {
      var dimsDef = coordDimInfo.dimsDef;
      return dimsDef ? dimsDef.length : 1;
    }

    encodeItemName.length && (encode.itemName = encodeItemName);
    encodeSeriesName.length && (encode.seriesName = encodeSeriesName);
    return encode;
  }

  function makeSeriesEncodeForNameBased(seriesModel, source, dimCount) {
    var encode = {};
    var datasetModel = querySeriesUpstreamDatasetModel(seriesModel);

    if (!datasetModel) {
      return encode;
    }

    var sourceFormat = source.sourceFormat;
    var dimensionsDefine = source.dimensionsDefine;
    var potentialNameDimIndex;

    if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
      each(dimensionsDefine, function (dim, idx) {
        if ((isObject(dim) ? dim.name : dim) === 'name') {
          potentialNameDimIndex = idx;
        }
      });
    }

    var idxResult = function () {
      var idxRes0 = {};
      var idxRes1 = {};
      var guessRecords = [];

      for (var i = 0, len = Math.min(5, dimCount); i < len; i++) {
        var guessResult = doGuessOrdinal(source.data, sourceFormat, source.seriesLayoutBy, dimensionsDefine, source.startIndex, i);
        guessRecords.push(guessResult);
        var isPureNumber = guessResult === BE_ORDINAL.Not;

        if (isPureNumber && idxRes0.v == null && i !== potentialNameDimIndex) {
          idxRes0.v = i;
        }

        if (idxRes0.n == null || idxRes0.n === idxRes0.v || !isPureNumber && guessRecords[idxRes0.n] === BE_ORDINAL.Not) {
          idxRes0.n = i;
        }

        if (fulfilled(idxRes0) && guessRecords[idxRes0.n] !== BE_ORDINAL.Not) {
          return idxRes0;
        }

        if (!isPureNumber) {
          if (guessResult === BE_ORDINAL.Might && idxRes1.v == null && i !== potentialNameDimIndex) {
            idxRes1.v = i;
          }

          if (idxRes1.n == null || idxRes1.n === idxRes1.v) {
            idxRes1.n = i;
          }
        }
      }

      function fulfilled(idxResult) {
        return idxResult.v != null && idxResult.n != null;
      }

      return fulfilled(idxRes0) ? idxRes0 : fulfilled(idxRes1) ? idxRes1 : null;
    }();

    if (idxResult) {
      encode.value = [idxResult.v];
      var nameDimIndex = potentialNameDimIndex != null ? potentialNameDimIndex : idxResult.n;
      encode.itemName = [nameDimIndex];
      encode.seriesName = [nameDimIndex];
    }

    return encode;
  }

  function querySeriesUpstreamDatasetModel(seriesModel) {
    var thisData = seriesModel.get('data', true);

    if (!thisData) {
      return queryReferringComponents(seriesModel.ecModel, 'dataset', {
        index: seriesModel.get('datasetIndex', true),
        id: seriesModel.get('datasetId', true)
      }, SINGLE_REFERRING).models[0];
    }
  }

  function queryDatasetUpstreamDatasetModels(datasetModel) {
    if (!datasetModel.get('transform', true) && !datasetModel.get('fromTransformResult', true)) {
      return [];
    }

    return queryReferringComponents(datasetModel.ecModel, 'dataset', {
      index: datasetModel.get('fromDatasetIndex', true),
      id: datasetModel.get('fromDatasetId', true)
    }, SINGLE_REFERRING).models;
  }

  function guessOrdinal(source, dimIndex) {
    return doGuessOrdinal(source.data, source.sourceFormat, source.seriesLayoutBy, source.dimensionsDefine, source.startIndex, dimIndex);
  }

  function doGuessOrdinal(data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex) {
    var result;
    var maxLoop = 5;

    if (isTypedArray(data)) {
      return BE_ORDINAL.Not;
    }

    var dimName;
    var dimType;

    if (dimensionsDefine) {
      var dimDefItem = dimensionsDefine[dimIndex];

      if (isObject(dimDefItem)) {
        dimName = dimDefItem.name;
        dimType = dimDefItem.type;
      } else if (isString(dimDefItem)) {
        dimName = dimDefItem;
      }
    }

    if (dimType != null) {
      return dimType === 'ordinal' ? BE_ORDINAL.Must : BE_ORDINAL.Not;
    }

    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
      var dataArrayRows = data;

      if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {
        var sample = dataArrayRows[dimIndex];

        for (var i = 0; i < (sample || []).length && i < maxLoop; i++) {
          if ((result = detectValue(sample[startIndex + i])) != null) {
            return result;
          }
        }
      } else {
        for (var i = 0; i < dataArrayRows.length && i < maxLoop; i++) {
          var row = dataArrayRows[startIndex + i];

          if (row && (result = detectValue(row[dimIndex])) != null) {
            return result;
          }
        }
      }
    } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
      var dataObjectRows = data;

      if (!dimName) {
        return BE_ORDINAL.Not;
      }

      for (var i = 0; i < dataObjectRows.length && i < maxLoop; i++) {
        var item = dataObjectRows[i];

        if (item && (result = detectValue(item[dimName])) != null) {
          return result;
        }
      }
    } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
      var dataKeyedColumns = data;

      if (!dimName) {
        return BE_ORDINAL.Not;
      }

      var sample = dataKeyedColumns[dimName];

      if (!sample || isTypedArray(sample)) {
        return BE_ORDINAL.Not;
      }

      for (var i = 0; i < sample.length && i < maxLoop; i++) {
        if ((result = detectValue(sample[i])) != null) {
          return result;
        }
      }
    } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {
      var dataOriginal = data;

      for (var i = 0; i < dataOriginal.length && i < maxLoop; i++) {
        var item = dataOriginal[i];
        var val = getDataItemValue(item);

        if (!isArray(val)) {
          return BE_ORDINAL.Not;
        }

        if ((result = detectValue(val[dimIndex])) != null) {
          return result;
        }
      }
    }

    function detectValue(val) {
      var beStr = isString(val);

      if (val != null && isFinite(val) && val !== '') {
        return beStr ? BE_ORDINAL.Might : BE_ORDINAL.Not;
      } else if (beStr && val !== '-') {
        return BE_ORDINAL.Must;
      }
    }

    return BE_ORDINAL.Not;
  }

  var internalOptionCreatorMap = createHashMap();

  function concatInternalOptions(ecModel, mainType, newCmptOptionList) {
    var internalOptionCreator = internalOptionCreatorMap.get(mainType);

    if (!internalOptionCreator) {
      return newCmptOptionList;
    }

    var internalOptions = internalOptionCreator(ecModel);

    if (!internalOptions) {
      return newCmptOptionList;
    }

    if (true) {
      for (var i = 0; i < internalOptions.length; i++) {
        assert(isComponentIdInternal(internalOptions[i]));
      }
    }

    return newCmptOptionList.concat(internalOptions);
  }

  var reCreateSeriesIndices;
  var assertSeriesInitialized;
  var initBase;
  var OPTION_INNER_KEY = '\0_ec_inner';

  var GlobalModel = function (_super) {
    __extends(GlobalModel, _super);

    function GlobalModel() {
      return _super !== null && _super.apply(this, arguments) || this;
    }

    GlobalModel.prototype.init = function (option, parentModel, ecModel, theme, locale, optionManager) {
      theme = theme || {};
      this.option = null;
      this._theme = new Model(theme);
      this._locale = new Model(locale);
      this._optionManager = optionManager;
    };

    GlobalModel.prototype.setOption = function (option, opts, optionPreprocessorFuncs) {
      assert(!(OPTION_INNER_KEY in option), 'please use chart.getOption()');
      var innerOpt = normalizeReplaceMergeInput(opts);

      this._optionManager.setOption(option, optionPreprocessorFuncs, innerOpt);

      this._resetOption(null, innerOpt);
    };

    GlobalModel.prototype.resetOption = function (type, opt) {
      return this._resetOption(type, normalizeReplaceMergeInput(opt));
    };

    GlobalModel.prototype._resetOption = function (type, opt) {
      var optionChanged = false;
      var optionManager = this._optionManager;

      if (!type || type === 'recreate') {
        var baseOption = optionManager.mountOption(type === 'recreate');

        if (!this.option || type === 'recreate') {
          initBase(this, baseOption);
        } else {
          this.restoreData();

          this._mergeOption(baseOption, opt);
        }

        optionChanged = true;
      }

      if (type === 'timeline' || type === 'media') {
        this.restoreData();
      }

      if (!type || type === 'recreate' || type === 'timeline') {
        var timelineOption = optionManager.getTimelineOption(this);

        if (timelineOption) {
          optionChanged = true;

          this._mergeOption(timelineOption, opt);
        }
      }

      if (!type || type === 'recreate' || type === 'media') {
        var mediaOptions = optionManager.getMediaOption(this);

        if (mediaOptions.length) {
          each(mediaOptions, function (mediaOption) {
            optionChanged = true;

            this._mergeOption(mediaOption, opt);
          }, this);
        }
      }

      return optionChanged;
    };

    GlobalModel.prototype.mergeOption = function (option) {
      this._mergeOption(option, null);
    };

    GlobalModel.prototype._mergeOption = function (newOption, opt) {
      var option = this.option;
      var componentsMap = this._componentsMap;
      var componentsCount = this._componentsCount;
      var newCmptTypes = [];
      var newCmptTypeMap = createHashMap();
      var replaceMergeMainTypeMap = opt && opt.replaceMergeMainTypeMap;
      resetSourceDefaulter(this);
      each(newOption, function (componentOption, mainType) {
        if (componentOption == null) {
          return;
        }

        if (!ComponentModel.hasClass(mainType)) {
          option[mainType] = option[mainType] == null ? clone(componentOption) : merge(option[mainType], componentOption, true);
        } else if (mainType) {
          newCmptTypes.push(mainType);
          newCmptTypeMap.set(mainType, true);
        }
      });

      if (replaceMergeMainTypeMap) {
        replaceMergeMainTypeMap.each(function (val, mainTypeInReplaceMerge) {
          if (!newCmptTypeMap.get(mainTypeInReplaceMerge)) {
            newCmptTypes.push(mainTypeInReplaceMerge);
            newCmptTypeMap.set(mainTypeInReplaceMerge, true);
          }
        });
      }

      ComponentModel.topologicalTravel(newCmptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this);

      function visitComponent(mainType) {
        var newCmptOptionList = concatInternalOptions(this, mainType, normalizeToArray(newOption[mainType]));
        var oldCmptList = componentsMap.get(mainType);
        var mergeMode = !oldCmptList ? 'replaceAll' : replaceMergeMainTypeMap && replaceMergeMainTypeMap.get(mainType) ? 'replaceMerge' : 'normalMerge';
        var mappingResult = mappingToExists(oldCmptList, newCmptOptionList, mergeMode);
        setComponentTypeToKeyInfo(mappingResult, mainType, ComponentModel);
        option[mainType] = null;
        componentsMap.set(mainType, null);
        componentsCount.set(mainType, 0);
        var optionsByMainType = [];
        var cmptsByMainType = [];
        var cmptsCountByMainType = 0;
        each(mappingResult, function (resultItem, index) {
          var componentModel = resultItem.existing;
          var newCmptOption = resultItem.newOption;

          if (!newCmptOption) {
            if (componentModel) {
              componentModel.mergeOption({}, this);
              componentModel.optionUpdated({}, false);
            }
          } else {
            var ComponentModelClass = ComponentModel.getClass(mainType, resultItem.keyInfo.subType, true);

            if (componentModel && componentModel.constructor === ComponentModelClass) {
              componentModel.name = resultItem.keyInfo.name;
              componentModel.mergeOption(newCmptOption, this);
              componentModel.optionUpdated(newCmptOption, false);
            } else {
              var extraOpt = extend({
                componentIndex: index
              }, resultItem.keyInfo);
              componentModel = new ComponentModelClass(newCmptOption, this, this, extraOpt);
              extend(componentModel, extraOpt);

              if (resultItem.brandNew) {
                componentModel.__requireNewView = true;
              }

              componentModel.init(newCmptOption, this, this);
              componentModel.optionUpdated(null, true);
            }
          }

          if (componentModel) {
            optionsByMainType.push(componentModel.option);
            cmptsByMainType.push(componentModel);
            cmptsCountByMainType++;
          } else {
            optionsByMainType.push(void 0);
            cmptsByMainType.push(void 0);
          }
        }, this);
        option[mainType] = optionsByMainType;
        componentsMap.set(mainType, cmptsByMainType);
        componentsCount.set(mainType, cmptsCountByMainType);

        if (mainType === 'series') {
          reCreateSeriesIndices(this);
        }
      }

      if (!this._seriesIndices) {
        reCreateSeriesIndices(this);
      }
    };

    GlobalModel.prototype.getOption = function () {
      var option = clone(this.option);
      each(option, function (optInMainType, mainType) {
        if (ComponentModel.hasClass(mainType)) {
          var opts = normalizeToArray(optInMainType);
          var realLen = opts.length;
          var metNonInner = false;

          for (var i = realLen - 1; i >= 0; i--) {
            if (opts[i] && !isComponentIdInternal(opts[i])) {
              metNonInner = true;
            } else {
              opts[i] = null;
              !metNonInner && realLen--;
            }
          }

          opts.length = realLen;
          option[mainType] = opts;
        }
      });
      delete option[OPTION_INNER_KEY];
      return option;
    };

    GlobalModel.prototype.getTheme = function () {
      return this._theme;
    };

    GlobalModel.prototype.getLocaleModel = function () {
      return this._locale;
    };

    GlobalModel.prototype.getLocale = function (localePosition) {
      var locale = this.getLocaleModel();
      return locale.get(localePosition);
    };

    GlobalModel.prototype.setUpdatePayload = function (payload) {
      this._payload = payload;
    };

    GlobalModel.prototype.getUpdatePayload = function () {
      return this._payload;
    };

    GlobalModel.prototype.getComponent = function (mainType, idx) {
      var list = this._componentsMap.get(mainType);

      if (list) {
        var cmpt = list[idx || 0];

        if (cmpt) {
          return cmpt;
        } else if (idx == null) {
          for (var i = 0; i < list.length; i++) {
            if (list[i]) {
              return list[i];
            }
          }
        }
      }
    };

    GlobalModel.prototype.queryComponents = function (condition) {
      var mainType = condition.mainType;

      if (!mainType) {
        return [];
      }

      var index = condition.index;
      var id = condition.id;
      var name = condition.name;

      var cmpts = this._componentsMap.get(mainType);

      if (!cmpts || !cmpts.length) {
        return [];
      }

      var result;

      if (index != null) {
        result = [];
        each(normalizeToArray(index), function (idx) {
          cmpts[idx] && result.push(cmpts[idx]);
        });
      } else if (id != null) {
        result = queryByIdOrName('id', id, cmpts);
      } else if (name != null) {
        result = queryByIdOrName('name', name, cmpts);
      } else {
        result = filter(cmpts, function (cmpt) {
          return !!cmpt;
        });
      }

      return filterBySubType(result, condition);
    };

    GlobalModel.prototype.findComponents = function (condition) {
      var query = condition.query;
      var mainType = condition.mainType;
      var queryCond = getQueryCond(query);
      var result = queryCond ? this.queryComponents(queryCond) : filter(this._componentsMap.get(mainType), function (cmpt) {
        return !!cmpt;
      });
      return doFilter(filterBySubType(result, condition));

      function getQueryCond(q) {
        var indexAttr = mainType + 'Index';
        var idAttr = mainType + 'Id';
        var nameAttr = mainType + 'Name';
        return q && (q[indexAttr] != null || q[idAttr] != null || q[nameAttr] != null) ? {
          mainType: mainType,
          index: q[indexAttr],
          id: q[idAttr],
          name: q[nameAttr]
        } : null;
      }

      function doFilter(res) {
        return condition.filter ? filter(res, condition.filter) : res;
      }
    };

    GlobalModel.prototype.eachComponent = function (mainType, cb, context) {
      var componentsMap = this._componentsMap;

      if (isFunction(mainType)) {
        var ctxForAll_1 = cb;
        var cbForAll_1 = mainType;
        componentsMap.each(function (cmpts, componentType) {
          for (var i = 0; cmpts && i < cmpts.length; i++) {
            var cmpt = cmpts[i];
            cmpt && cbForAll_1.call(ctxForAll_1, componentType, cmpt, cmpt.componentIndex);
          }
        });
      } else {
        var cmpts = isString(mainType) ? componentsMap.get(mainType) : isObject(mainType) ? this.findComponents(mainType) : null;

        for (var i = 0; cmpts && i < cmpts.length; i++) {
          var cmpt = cmpts[i];
          cmpt && cb.call(context, cmpt, cmpt.componentIndex);
        }
      }
    };

    GlobalModel.prototype.getSeriesByName = function (name) {
      return filter(this._componentsMap.get('series'), function (oneSeries) {
        return !!oneSeries && oneSeries.name === name;
      });
    };

    GlobalModel.prototype.getSeriesByIndex = function (seriesIndex) {
      return this._componentsMap.get('series')[seriesIndex];
    };

    GlobalModel.prototype.getSeriesByType = function (subType) {
      return filter(this._componentsMap.get('series'), function (oneSeries) {
        return !!oneSeries && oneSeries.subType === subType;
      });
    };

    GlobalModel.prototype.getSeries = function () {
      return filter(this._componentsMap.get('series').slice(), function (oneSeries) {
        return !!oneSeries;
      });
    };

    GlobalModel.prototype.getSeriesCount = function () {
      return this._componentsCount.get('series');
    };

    GlobalModel.prototype.eachSeries = function (cb, context) {
      assertSeriesInitialized(this);
      each(this._seriesIndices, function (rawSeriesIndex) {
        var series = this._componentsMap.get('series')[rawSeriesIndex];

        cb.call(context, series, rawSeriesIndex);
      }, this);
    };

    GlobalModel.prototype.eachRawSeries = function (cb, context) {
      each(this._componentsMap.get('series'), function (series) {
        series && cb.call(context, series, series.componentIndex);
      });
    };

    GlobalModel.prototype.eachSeriesByType = function (subType, cb, context) {
      assertSeriesInitialized(this);
      each(this._seriesIndices, function (rawSeriesIndex) {
        var series = this._componentsMap.get('series')[rawSeriesIndex];

        if (series.subType === subType) {
          cb.call(context, series, rawSeriesIndex);
        }
      }, this);
    };

    GlobalModel.prototype.eachRawSeriesByType = function (subType, cb, context) {
      return each(this.getSeriesByType(subType), cb, context);
    };

    GlobalModel.prototype.isSeriesFiltered = function (seriesModel) {
      assertSeriesInitialized(this);
      return this._seriesIndicesMap.get(seriesModel.componentIndex) == null;
    };

    GlobalModel.prototype.getCurrentSeriesIndices = function () {
      return (this._seriesIndices || []).slice();
    };

    GlobalModel.prototype.filterSeries = function (cb, context) {
      assertSeriesInitialized(this);
      var newSeriesIndices = [];
      each(this._seriesIndices, function (seriesRawIdx) {
        var series = this._componentsMap.get('series')[seriesRawIdx];

        cb.call(context, series, seriesRawIdx) && newSeriesIndices.push(seriesRawIdx);
      }, this);
      this._seriesIndices = newSeriesIndices;
      this._seriesIndicesMap = createHashMap(newSeriesIndices);
    };

    GlobalModel.prototype.restoreData = function (payload) {
      reCreateSeriesIndices(this);
      var componentsMap = this._componentsMap;
      var componentTypes = [];
      componentsMap.each(function (components, componentType) {
        componentTypes.push(componentType);
      });
      ComponentModel.topologicalTravel(componentTypes, ComponentModel.getAllClassMainTypes(), function (componentType) {
        each(componentsMap.get(componentType), function (component) {
          if (component && (componentType !== 'series' || !isNotTargetSeries(component, payload))) {
            component.restoreData();
          }
        });
      });
    };

    GlobalModel.internalField = function () {
      reCreateSeriesIndices = function (ecModel) {
        var seriesIndices = ecModel._seriesIndices = [];
        each(ecModel._componentsMap.get('series'), function (series) {
          series && seriesIndices.push(series.componentIndex);
        });
        ecModel._seriesIndicesMap = createHashMap(seriesIndices);
      };

      assertSeriesInitialized = function (ecModel) {
        if (true) {
          if (!ecModel._seriesIndices) {
            throw new Error('Option should contains series.');
          }
        }
      };

      initBase = function (ecModel, baseOption) {
        ecModel.option = {};
        ecModel.option[OPTION_INNER_KEY] = 1;
        ecModel._componentsMap = createHashMap({
          series: []
        });
        ecModel._componentsCount = createHashMap();
        mergeTheme(baseOption, ecModel._theme.option);
        merge(baseOption, globalDefault, false);

        ecModel._mergeOption(baseOption, null);
      };
    }();

    return GlobalModel;
  }(Model);

  function isNotTargetSeries(seriesModel, payload) {
    if (payload) {
      var index = payload.seriesIndex;
      var id = payload.seriesId;
      var name_1 = payload.seriesName;
      return index != null && seriesModel.componentIndex !== index || id != null && seriesModel.id !== id || name_1 != null && seriesModel.name !== name_1;
    }
  }

  function mergeTheme(option, theme) {
    var notMergeColorLayer = option.color && !option.colorLayer;
    each(theme, function (themeItem, name) {
      if (name === 'colorLayer' && notMergeColorLayer) {
        return;
      }

      if (!ComponentModel.hasClass(name)) {
        if (typeof themeItem === 'object') {
          option[name] = !option[name] ? clone(themeItem) : merge(option[name], themeItem, false);
        } else {
          if (option[name] == null) {
            option[name] = themeItem;
          }
        }
      }
    });
  }

  function queryByIdOrName(attr, idOrName, cmpts) {
    if (isArray(idOrName)) {
      var keyMap_1 = createHashMap(idOrName);
      each(idOrName, function (idOrNameItem) {
        if (idOrNameItem != null) {
          validateIdOrName(idOrNameItem);
          keyMap_1.set(idOrNameItem, true);
        }
      });
      return filter(cmpts, function (cmpt) {
        return cmpt && keyMap_1.get(cmpt[attr]);
      });
    } else {
      validateIdOrName(idOrName);
      return filter(cmpts, function (cmpt) {
        return cmpt && cmpt[attr] === idOrName + '';
      });
    }
  }

  function filterBySubType(components, condition) {
    return condition.hasOwnProperty('subType') ? filter(components, function (cmpt) {
      return cmpt && cmpt.subType === condition.subType;
    }) : components;
  }

  function normalizeReplaceMergeInput(opts) {
    var replaceMergeMainTypeMap = createHashMap();
    opts && each(normalizeToArray(opts.replaceMerge), function (mainType) {
      if (true) {
        assert(ComponentModel.hasClass(mainType), '"' + mainType + '" is not valid component main type in "replaceMerge"');
      }

      replaceMergeMainTypeMap.set(mainType, true);
    });
    return {
      replaceMergeMainTypeMap: replaceMergeMainTypeMap
    };
  }

  mixin(GlobalModel, ColorPaletteMixin);
  var availableMethods = ['getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isDisposed', 'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption', 'getViewOfComponentModel', 'getViewOfSeriesModel', 'getId', 'updateLabelLayout'];

  var ExtensionAPI = function () {
    function ExtensionAPI(ecInstance) {
      each(availableMethods, function (methodName) {
        this[methodName] = bind(ecInstance[methodName], ecInstance);
      }, this);
    }

    return ExtensionAPI;
  }();

  var coordinateSystemCreators = {};

  var CoordinateSystemManager = function () {
    function CoordinateSystemManager() {
      this._coordinateSystems = [];
    }

    CoordinateSystemManager.prototype.create = function (ecModel, api) {
      var coordinateSystems = [];
      each(coordinateSystemCreators, function (creater, type) {
        var list = creater.create(ecModel, api);
        coordinateSystems = coordinateSystems.concat(list || []);
      });
      this._coordinateSystems = coordinateSystems;
    };

    CoordinateSystemManager.prototype.update = function (ecModel, api) {
      each(this._coordinateSystems, function (coordSys) {
        coordSys.update && coordSys.update(ecModel, api);
      });
    };

    CoordinateSystemManager.prototype.getCoordinateSystems = function () {
      return this._coordinateSystems.slice();
    };

    CoordinateSystemManager.register = function (type, creator) {
      coordinateSystemCreators[type] = creator;
    };

    CoordinateSystemManager.get = function (type) {
      return coordinateSystemCreators[type];
    };

    return CoordinateSystemManager;
  }();

  var QUERY_REG = /^(min|max)?(.+)$/;

  var OptionManager = function () {
    function OptionManager(api) {
      this._timelineOptions = [];
      this._mediaList = [];
      this._currentMediaIndices = [];
      this._api = api;
    }

    OptionManager.prototype.setOption = function (rawOption, optionPreprocessorFuncs, opt) {
      if (rawOption) {
        each(normalizeToArray(rawOption.series), function (series) {
          series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data);
        });
        each(normalizeToArray(rawOption.dataset), function (dataset) {
          dataset && dataset.source && isTypedArray(dataset.source) && setAsPrimitive(dataset.source);
        });
      }

      rawOption = clone(rawOption);
      var optionBackup = this._optionBackup;
      var newParsedOption = parseRawOption(rawOption, optionPreprocessorFuncs, !optionBackup);
      this._newBaseOption = newParsedOption.baseOption;

      if (optionBackup) {
        if (newParsedOption.timelineOptions.length) {
          optionBackup.timelineOptions = newParsedOption.timelineOptions;
        }

        if (newParsedOption.mediaList.length) {
          optionBackup.mediaList = newParsedOption.mediaList;
        }

        if (newParsedOption.mediaDefault) {
          optionBackup.mediaDefault = newParsedOption.mediaDefault;
        }
      } else {
        this._optionBackup = newParsedOption;
      }
    };

    OptionManager.prototype.mountOption = function (isRecreate) {
      var optionBackup = this._optionBackup;
      this._timelineOptions = optionBackup.timelineOptions;
      this._mediaList = optionBackup.mediaList;
      this._mediaDefault = optionBackup.mediaDefault;
      this._currentMediaIndices = [];
      return clone(isRecreate ? optionBackup.baseOption : this._newBaseOption);
    };

    OptionManager.prototype.getTimelineOption = function (ecModel) {
      var option;
      var timelineOptions = this._timelineOptions;

      if (timelineOptions.length) {
        var timelineModel = ecModel.getComponent('timeline');

        if (timelineModel) {
          option = clone(timelineOptions[timelineModel.getCurrentIndex()]);
        }
      }

      return option;
    };

    OptionManager.prototype.getMediaOption = function (ecModel) {
      var ecWidth = this._api.getWidth();

      var ecHeight = this._api.getHeight();

      var mediaList = this._mediaList;
      var mediaDefault = this._mediaDefault;
      var indices = [];
      var result = [];

      if (!mediaList.length && !mediaDefault) {
        return result;
      }

      for (var i = 0, len = mediaList.length; i < len; i++) {
        if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) {
          indices.push(i);
        }
      }

      if (!indices.length && mediaDefault) {
        indices = [-1];
      }

      if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) {
        result = map(indices, function (index) {
          return clone(index === -1 ? mediaDefault.option : mediaList[index].option);
        });
      }

      this._currentMediaIndices = indices;
      return result;
    };

    return OptionManager;
  }();

  function parseRawOption(rawOption, optionPreprocessorFuncs, isNew) {
    var timelineOptions = [];
    var mediaList = [];
    var mediaDefault;
    var baseOption;
    var timelineOpt = rawOption.timeline;

    if (rawOption.baseOption) {
      baseOption = rawOption.baseOption;
    }

    if (timelineOpt || rawOption.options) {
      baseOption = baseOption || {};
      timelineOptions = (rawOption.options || []).slice();
    }

    if (rawOption.media) {
      baseOption = baseOption || {};
      var media = rawOption.media;
      each(media, function (singleMedia) {
        if (singleMedia && singleMedia.option) {
          if (singleMedia.query) {
            mediaList.push(singleMedia);
          } else if (!mediaDefault) {
            mediaDefault = singleMedia;
          }
        }
      });
    }

    if (!baseOption) {
      baseOption = rawOption;
    }

    if (!baseOption.timeline) {
      baseOption.timeline = timelineOpt;
    }

    each([baseOption].concat(timelineOptions).concat(map(mediaList, function (media) {
      return media.option;
    })), function (option) {
      each(optionPreprocessorFuncs, function (preProcess) {
        preProcess(option, isNew);
      });
    });
    return {
      baseOption: baseOption,
      timelineOptions: timelineOptions,
      mediaDefault: mediaDefault,
      mediaList: mediaList
    };
  }

  function applyMediaQuery(query, ecWidth, ecHeight) {
    var realMap = {
      width: ecWidth,
      height: ecHeight,
      aspectratio: ecWidth / ecHeight
    };
    var applicatable = true;
    each(query, function (value, attr) {
      var matched = attr.match(QUERY_REG);

      if (!matched || !matched[1] || !matched[2]) {
        return;
      }

      var operator = matched[1];
      var realAttr = matched[2].toLowerCase();

      if (!compare(realMap[realAttr], value, operator)) {
        applicatable = false;
      }
    });
    return applicatable;
  }

  function compare(real, expect, operator) {
    if (operator === 'min') {
      return real >= expect;
    } else if (operator === 'max') {
      return real <= expect;
    } else {
      return real === expect;
    }
  }

  function indicesEquals(indices1, indices2) {
    return indices1.join(',') === indices2.join(',');
  }

  var each$2 = each;
  var isObject$1 = isObject;
  var POSSIBLE_STYLES = ['areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle', 'chordStyle', 'label', 'labelLine'];

  function compatEC2ItemStyle(opt) {
    var itemStyleOpt = opt && opt.itemStyle;

    if (!itemStyleOpt) {
      return;
    }

    for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) {
      var styleName = POSSIBLE_STYLES[i];
      var normalItemStyleOpt = itemStyleOpt.normal;
      var emphasisItemStyleOpt = itemStyleOpt.emphasis;

      if (normalItemStyleOpt && normalItemStyleOpt[styleName]) {
        if (true) {
          deprecateReplaceLog("itemStyle.normal." + styleName, styleName);
        }

        opt[styleName] = opt[styleName] || {};

        if (!opt[styleName].normal) {
          opt[styleName].normal = normalItemStyleOpt[styleName];
        } else {
          merge(opt[styleName].normal, normalItemStyleOpt[styleName]);
        }

        normalItemStyleOpt[styleName] = null;
      }

      if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) {
        if (true) {
          deprecateReplaceLog("itemStyle.emphasis." + styleName, "emphasis." + styleName);
        }

        opt[styleName] = opt[styleName] || {};

        if (!opt[styleName].emphasis) {
          opt[styleName].emphasis = emphasisItemStyleOpt[styleName];
        } else {
          merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]);
        }

        emphasisItemStyleOpt[styleName] = null;
      }
    }
  }

  function convertNormalEmphasis(opt, optType, useExtend) {
    if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) {
      var normalOpt = opt[optType].normal;
      var emphasisOpt = opt[optType].emphasis;

      if (normalOpt) {
        if (true) {
          deprecateLog("'normal' hierarchy in " + optType + " has been removed since 4.0. All style properties are configured in " + optType + " directly now.");
        }

        if (useExtend) {
          opt[optType].normal = opt[optType].emphasis = null;
          defaults(opt[optType], normalOpt);
        } else {
          opt[optType] = normalOpt;
        }
      }

      if (emphasisOpt) {
        if (true) {
          deprecateLog(optType + ".emphasis has been changed to emphasis." + optType + " since 4.0");
        }

        opt.emphasis = opt.emphasis || {};
        opt.emphasis[optType] = emphasisOpt;

        if (emphasisOpt.focus) {
          opt.emphasis.focus = emphasisOpt.focus;
        }

        if (emphasisOpt.blurScope) {
          opt.emphasis.blurScope = emphasisOpt.blurScope;
        }
      }
    }
  }

  function removeEC3NormalStatus(opt) {
    convertNormalEmphasis(opt, 'itemStyle');
    convertNormalEmphasis(opt, 'lineStyle');
    convertNormalEmphasis(opt, 'areaStyle');
    convertNormalEmphasis(opt, 'label');
    convertNormalEmphasis(opt, 'labelLine');
    convertNormalEmphasis(opt, 'upperLabel');
    convertNormalEmphasis(opt, 'edgeLabel');
  }

  function compatTextStyle(opt, propName) {
    var labelOptSingle = isObject$1(opt) && opt[propName];
    var textStyle = isObject$1(labelOptSingle) && labelOptSingle.textStyle;

    if (textStyle) {
      if (true) {
        deprecateLog("textStyle hierarchy in " + propName + " has been removed since 4.0. All textStyle properties are configured in " + propName + " directly now.");
      }

      for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) {
        var textPropName = TEXT_STYLE_OPTIONS[i];

        if (textStyle.hasOwnProperty(textPropName)) {
          labelOptSingle[textPropName] = textStyle[textPropName];
        }
      }
    }
  }

  function compatEC3CommonStyles(opt) {
    if (opt) {
      removeEC3NormalStatus(opt);
      compatTextStyle(opt, 'label');
      opt.emphasis && compatTextStyle(opt.emphasis, 'label');
    }
  }

  function processSeries(seriesOpt) {
    if (!isObject$1(seriesOpt)) {
      return;
    }

    compatEC2ItemStyle(seriesOpt);
    removeEC3NormalStatus(seriesOpt);
    compatTextStyle(seriesOpt, 'label');
    compatTextStyle(seriesOpt, 'upperLabel');
    compatTextStyle(seriesOpt, 'edgeLabel');

    if (seriesOpt.emphasis) {
      compatTextStyle(seriesOpt.emphasis, 'label');
      compatTextStyle(seriesOpt.emphasis, 'upperLabel');
      compatTextStyle(seriesOpt.emphasis, 'edgeLabel');
    }

    var markPoint = seriesOpt.markPoint;

    if (markPoint) {
      compatEC2ItemStyle(markPoint);
      compatEC3CommonStyles(markPoint);
    }

    var markLine = seriesOpt.markLine;

    if (markLine) {
      compatEC2ItemStyle(markLine);
      compatEC3CommonStyles(markLine);
    }

    var markArea = seriesOpt.markArea;

    if (markArea) {
      compatEC3CommonStyles(markArea);
    }

    var data = seriesOpt.data;

    if (seriesOpt.type === 'graph') {
      data = data || seriesOpt.nodes;
      var edgeData = seriesOpt.links || seriesOpt.edges;

      if (edgeData && !isTypedArray(edgeData)) {
        for (var i = 0; i < edgeData.length; i++) {
          compatEC3CommonStyles(edgeData[i]);
        }
      }

      each(seriesOpt.categories, function (opt) {
        removeEC3NormalStatus(opt);
      });
    }

    if (data && !isTypedArray(data)) {
      for (var i = 0; i < data.length; i++) {
        compatEC3CommonStyles(data[i]);
      }
    }

    markPoint = seriesOpt.markPoint;

    if (markPoint && markPoint.data) {
      var mpData = markPoint.data;

      for (var i = 0; i < mpData.length; i++) {
        compatEC3CommonStyles(mpData[i]);
      }
    }

    markLine = seriesOpt.markLine;

    if (markLine && markLine.data) {
      var mlData = markLine.data;

      for (var i = 0; i < mlData.length; i++) {
        if (isArray(mlData[i])) {
          compatEC3CommonStyles(mlData[i][0]);
          compatEC3CommonStyles(mlData[i][1]);
        } else {
          compatEC3CommonStyles(mlData[i]);
        }
      }
    }

    if (seriesOpt.type === 'gauge') {
      compatTextStyle(seriesOpt, 'axisLabel');
      compatTextStyle(seriesOpt, 'title');
      compatTextStyle(seriesOpt, 'detail');
    } else if (seriesOpt.type === 'treemap') {
      convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle');
      each(seriesOpt.levels, function (opt) {
        removeEC3NormalStatus(opt);
      });
    } else if (seriesOpt.type === 'tree') {
      removeEC3NormalStatus(seriesOpt.leaves);
    }
  }

  function toArr(o) {
    return isArray(o) ? o : o ? [o] : [];
  }

  function toObj(o) {
    return (isArray(o) ? o[0] : o) || {};
  }

  function compatStyle(option, isTheme) {
    each$2(toArr(option.series), function (seriesOpt) {
      isObject$1(seriesOpt) && processSeries(seriesOpt);
    });
    var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar'];
    isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis');
    each$2(axes, function (axisName) {
      each$2(toArr(option[axisName]), function (axisOpt) {
        if (axisOpt) {
          compatTextStyle(axisOpt, 'axisLabel');
          compatTextStyle(axisOpt.axisPointer, 'label');
        }
      });
    });
    each$2(toArr(option.parallel), function (parallelOpt) {
      var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault;
      compatTextStyle(parallelAxisDefault, 'axisLabel');
      compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label');
    });
    each$2(toArr(option.calendar), function (calendarOpt) {
      convertNormalEmphasis(calendarOpt, 'itemStyle');
      compatTextStyle(calendarOpt, 'dayLabel');
      compatTextStyle(calendarOpt, 'monthLabel');
      compatTextStyle(calendarOpt, 'yearLabel');
    });
    each$2(toArr(option.radar), function (radarOpt) {
      compatTextStyle(radarOpt, 'name');

      if (radarOpt.name && radarOpt.axisName == null) {
        radarOpt.axisName = radarOpt.name;
        delete radarOpt.name;

        if (true) {
          deprecateLog('name property in radar component has been changed to axisName');
        }
      }

      if (radarOpt.nameGap != null && radarOpt.axisNameGap == null) {
        radarOpt.axisNameGap = radarOpt.nameGap;
        delete radarOpt.nameGap;

        if (true) {
          deprecateLog('nameGap property in radar component has been changed to axisNameGap');
        }
      }
    });
    each$2(toArr(option.geo), function (geoOpt) {
      if (isObject$1(geoOpt)) {
        compatEC3CommonStyles(geoOpt);
        each$2(toArr(geoOpt.regions), function (regionObj) {
          compatEC3CommonStyles(regionObj);
        });
      }
    });
    each$2(toArr(option.timeline), function (timelineOpt) {
      compatEC3CommonStyles(timelineOpt);
      convertNormalEmphasis(timelineOpt, 'label');
      convertNormalEmphasis(timelineOpt, 'itemStyle');
      convertNormalEmphasis(timelineOpt, 'controlStyle', true);
      var data = timelineOpt.data;
      isArray(data) && each(data, function (item) {
        if (isObject(item)) {
          convertNormalEmphasis(item, 'label');
          convertNormalEmphasis(item, 'itemStyle');
        }
      });
    });
    each$2(toArr(option.toolbox), function (toolboxOpt) {
      convertNormalEmphasis(toolboxOpt, 'iconStyle');
      each$2(toolboxOpt.feature, function (featureOpt) {
        convertNormalEmphasis(featureOpt, 'iconStyle');
      });
    });
    compatTextStyle(toObj(option.axisPointer), 'label');
    compatTextStyle(toObj(option.tooltip).axisPointer, 'label');
  }

  function get(opt, path) {
    var pathArr = path.split(',');
    var obj = opt;

    for (var i = 0; i < pathArr.length; i++) {
      obj = obj && obj[pathArr[i]];

      if (obj == null) {
        break;
      }
    }

    return obj;
  }

  function set(opt, path, val, overwrite) {
    var pathArr = path.split(',');
    var obj = opt;
    var key;
    var i = 0;

    for (; i < pathArr.length - 1; i++) {
      key = pathArr[i];

      if (obj[key] == null) {
        obj[key] = {};
      }

      obj = obj[key];
    }

    if (overwrite || obj[pathArr[i]] == null) {
      obj[pathArr[i]] = val;
    }
  }

  function compatLayoutProperties(option) {
    option && each(LAYOUT_PROPERTIES, function (prop) {
      if (prop[0] in option && !(prop[1] in option)) {
        option[prop[1]] = option[prop[0]];
      }
    });
  }

  var LAYOUT_PROPERTIES = [['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']];
  var COMPATITABLE_COMPONENTS = ['grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline'];
  var BAR_ITEM_STYLE_MAP = [['borderRadius', 'barBorderRadius'], ['borderColor', 'barBorderColor'], ['borderWidth', 'barBorderWidth']];

  function compatBarItemStyle(option) {
    var itemStyle = option && option.itemStyle;

    if (itemStyle) {
      for (var i = 0; i < BAR_ITEM_STYLE_MAP.length; i++) {
        var oldName = BAR_ITEM_STYLE_MAP[i][1];
        var newName = BAR_ITEM_STYLE_MAP[i][0];

        if (itemStyle[oldName] != null) {
          itemStyle[newName] = itemStyle[oldName];

          if (true) {
            deprecateReplaceLog(oldName, newName);
          }
        }
      }
    }
  }

  function compatPieLabel(option) {
    if (!option) {
      return;
    }

    if (option.alignTo === 'edge' && option.margin != null && option.edgeDistance == null) {
      if (true) {
        deprecateReplaceLog('label.margin', 'label.edgeDistance', 'pie');
      }

      option.edgeDistance = option.margin;
    }
  }

  function compatSunburstState(option) {
    if (!option) {
      return;
    }

    if (option.downplay && !option.blur) {
      option.blur = option.downplay;

      if (true) {
        deprecateReplaceLog('downplay', 'blur', 'sunburst');
      }
    }
  }

  function compatGraphFocus(option) {
    if (!option) {
      return;
    }

    if (option.focusNodeAdjacency != null) {
      option.emphasis = option.emphasis || {};

      if (option.emphasis.focus == null) {
        if (true) {
          deprecateReplaceLog('focusNodeAdjacency', 'emphasis: { focus: \'adjacency\'}', 'graph/sankey');
        }

        option.emphasis.focus = 'adjacency';
      }
    }
  }

  function traverseTree(data, cb) {
    if (data) {
      for (var i = 0; i < data.length; i++) {
        cb(data[i]);
        data[i] && traverseTree(data[i].children, cb);
      }
    }
  }

  function backwardCompat(option, isTheme) {
    compatStyle(option, isTheme);
    option.series = normalizeToArray(option.series);
    each(option.series, function (seriesOpt) {
      if (!isObject(seriesOpt)) {
        return;
      }

      var seriesType = seriesOpt.type;

      if (seriesType === 'line') {
        if (seriesOpt.clipOverflow != null) {
          seriesOpt.clip = seriesOpt.clipOverflow;

          if (true) {
            deprecateReplaceLog('clipOverflow', 'clip', 'line');
          }
        }
      } else if (seriesType === 'pie' || seriesType === 'gauge') {
        if (seriesOpt.clockWise != null) {
          seriesOpt.clockwise = seriesOpt.clockWise;

          if (true) {
            deprecateReplaceLog('clockWise', 'clockwise');
          }
        }

        compatPieLabel(seriesOpt.label);
        var data = seriesOpt.data;

        if (data && !isTypedArray(data)) {
          for (var i = 0; i < data.length; i++) {
            compatPieLabel(data[i]);
          }
        }

        if (seriesOpt.hoverOffset != null) {
          seriesOpt.emphasis = seriesOpt.emphasis || {};

          if (seriesOpt.emphasis.scaleSize = null) {
            if (true) {
              deprecateReplaceLog('hoverOffset', 'emphasis.scaleSize');
            }

            seriesOpt.emphasis.scaleSize = seriesOpt.hoverOffset;
          }
        }
      } else if (seriesType === 'gauge') {
        var pointerColor = get(seriesOpt, 'pointer.color');
        pointerColor != null && set(seriesOpt, 'itemStyle.color', pointerColor);
      } else if (seriesType === 'bar') {
        compatBarItemStyle(seriesOpt);
        compatBarItemStyle(seriesOpt.backgroundStyle);
        compatBarItemStyle(seriesOpt.emphasis);
        var data = seriesOpt.data;

        if (data && !isTypedArray(data)) {
          for (var i = 0; i < data.length; i++) {
            if (typeof data[i] === 'object') {
              compatBarItemStyle(data[i]);
              compatBarItemStyle(data[i] && data[i].emphasis);
            }
          }
        }
      } else if (seriesType === 'sunburst') {
        var highlightPolicy = seriesOpt.highlightPolicy;

        if (highlightPolicy) {
          seriesOpt.emphasis = seriesOpt.emphasis || {};

          if (!seriesOpt.emphasis.focus) {
            seriesOpt.emphasis.focus = highlightPolicy;

            if (true) {
              deprecateReplaceLog('highlightPolicy', 'emphasis.focus', 'sunburst');
            }
          }
        }

        compatSunburstState(seriesOpt);
        traverseTree(seriesOpt.data, compatSunburstState);
      } else if (seriesType === 'graph' || seriesType === 'sankey') {
        compatGraphFocus(seriesOpt);
      } else if (seriesType === 'map') {
        if (seriesOpt.mapType && !seriesOpt.map) {
          if (true) {
            deprecateReplaceLog('mapType', 'map', 'map');
          }

          seriesOpt.map = seriesOpt.mapType;
        }

        if (seriesOpt.mapLocation) {
          if (true) {
            deprecateLog('`mapLocation` is not used anymore.');
          }

          defaults(seriesOpt, seriesOpt.mapLocation);
        }
      }

      if (seriesOpt.hoverAnimation != null) {
        seriesOpt.emphasis = seriesOpt.emphasis || {};

        if (seriesOpt.emphasis && seriesOpt.emphasis.scale == null) {
          if (true) {
            deprecateReplaceLog('hoverAnimation', 'emphasis.scale');
          }

          seriesOpt.emphasis.scale = seriesOpt.hoverAnimation;
        }
      }

      compatLayoutProperties(seriesOpt);
    });

    if (option.dataRange) {
      option.visualMap = option.dataRange;
    }

    each(COMPATITABLE_COMPONENTS, function (componentName) {
      var options = option[componentName];

      if (options) {
        if (!isArray(options)) {
          options = [options];
        }

        each(options, function (option) {
          compatLayoutProperties(option);
        });
      }
    });
  }

  function dataStack(ecModel) {
    var stackInfoMap = createHashMap();
    ecModel.eachSeries(function (seriesModel) {
      var stack = seriesModel.get('stack');

      if (stack) {
        var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []);
        var data = seriesModel.getData();
        var stackInfo = {
          stackResultDimension: data.getCalculationInfo('stackResultDimension'),
          stackedOverDimension: data.getCalculationInfo('stackedOverDimension'),
          stackedDimension: data.getCalculationInfo('stackedDimension'),
          stackedByDimension: data.getCalculationInfo('stackedByDimension'),
          isStackedByIndex: data.getCalculationInfo('isStackedByIndex'),
          data: data,
          seriesModel: seriesModel
        };

        if (!stackInfo.stackedDimension || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)) {
          return;
        }

        stackInfoList.length && data.setCalculationInfo('stackedOnSeries', stackInfoList[stackInfoList.length - 1].seriesModel);
        stackInfoList.push(stackInfo);
      }
    });
    stackInfoMap.each(calculateStack);
  }

  function calculateStack(stackInfoList) {
    each(stackInfoList, function (targetStackInfo, idxInStack) {
      var resultVal = [];
      var resultNaN = [NaN, NaN];
      var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension];
      var targetData = targetStackInfo.data;
      var isStackedByIndex = targetStackInfo.isStackedByIndex;
      var newData = targetData.map(dims, function (v0, v1, dataIndex) {
        var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex);

        if (isNaN(sum)) {
          return resultNaN;
        }

        var byValue;
        var stackedDataRawIndex;

        if (isStackedByIndex) {
          stackedDataRawIndex = targetData.getRawIndex(dataIndex);
        } else {
          byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex);
        }

        var stackedOver = NaN;

        for (var j = idxInStack - 1; j >= 0; j--) {
          var stackInfo = stackInfoList[j];

          if (!isStackedByIndex) {
            stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue);
          }

          if (stackedDataRawIndex >= 0) {
            var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex);

            if (sum >= 0 && val > 0 || sum <= 0 && val < 0) {
              sum += val;
              stackedOver = val;
              break;
            }
          }
        }

        resultVal[0] = sum;
        resultVal[1] = stackedOver;
        return resultVal;
      });
      targetData.hostModel.setData(newData);
      targetStackInfo.data = newData;
    });
  }

  var _a, _b, _c;

  var providerMethods;
  var mountMethods;

  var DefaultDataProvider = function () {
    function DefaultDataProvider(sourceParam, dimSize) {
      var source = !(sourceParam instanceof Source) ? Source.seriesDataToSource(sourceParam) : sourceParam;
      this._source = source;
      var data = this._data = source.data;

      if (source.sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {
        if (true) {
          if (dimSize == null) {
            throw new Error('Typed array data must specify dimension size');
          }
        }

        this._offset = 0;
        this._dimSize = dimSize;
        this._data = data;
      }

      mountMethods(this, data, source);
    }

    DefaultDataProvider.prototype.getSource = function () {
      return this._source;
    };

    DefaultDataProvider.prototype.count = function () {
      return 0;
    };

    DefaultDataProvider.prototype.getItem = function (idx, out) {
      return;
    };

    DefaultDataProvider.prototype.appendData = function (newData) {};

    DefaultDataProvider.prototype.clean = function () {};

    DefaultDataProvider.protoInitialize = function () {
      var proto = DefaultDataProvider.prototype;
      proto.pure = false;
      proto.persistent = true;
    }();

    DefaultDataProvider.internalField = function () {
      var _a;

      mountMethods = function (provider, data, source) {
        var sourceFormat = source.sourceFormat;
        var seriesLayoutBy = source.seriesLayoutBy;
        var startIndex = source.startIndex;
        var dimsDef = source.dimensionsDefine;
        var methods = providerMethods[getMethodMapKey(sourceFormat, seriesLayoutBy)];

        if (true) {
          assert(methods, 'Invalide sourceFormat: ' + sourceFormat);
        }

        extend(provider, methods);

        if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {
          provider.getItem = getItemForTypedArray;
          provider.count = countForTypedArray;
        } else {
          var rawItemGetter = getRawSourceItemGetter(sourceFormat, seriesLayoutBy);
          provider.getItem = bind(rawItemGetter, null, data, startIndex, dimsDef);
          var rawCounter = getRawSourceDataCounter(sourceFormat, seriesLayoutBy);
          provider.count = bind(rawCounter, null, data, startIndex, dimsDef);
        }
      };

      var getItemForTypedArray = function (idx, out) {
        idx = idx - this._offset;
        out = out || [];
        var offset = this._dimSize * idx;

        for (var i = 0; i < this._dimSize; i++) {
          out[i] = this._data[offset + i];
        }

        return out;
      };

      var countForTypedArray = function () {
        return this._data ? this._data.length / this._dimSize : 0;
      };

      providerMethods = (_a = {}, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = {
        pure: true,
        appendData: appendDataSimply
      }, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = {
        pure: true,
        appendData: function () {
          throw new Error('Do not support appendData when set seriesLayoutBy: "row".');
        }
      }, _a[SOURCE_FORMAT_OBJECT_ROWS] = {
        pure: true,
        appendData: appendDataSimply
      }, _a[SOURCE_FORMAT_KEYED_COLUMNS] = {
        pure: true,
        appendData: function (newData) {
          var data = this._data;
          each(newData, function (newCol, key) {
            var oldCol = data[key] || (data[key] = []);

            for (var i = 0; i < (newCol || []).length; i++) {
              oldCol.push(newCol[i]);
            }
          });
        }
      }, _a[SOURCE_FORMAT_ORIGINAL] = {
        appendData: appendDataSimply
      }, _a[SOURCE_FORMAT_TYPED_ARRAY] = {
        persistent: false,
        pure: true,
        appendData: function (newData) {
          if (true) {
            assert(isTypedArray(newData), 'Added data must be TypedArray if data in initialization is TypedArray');
          }

          this._data = newData;
        },
        clean: function () {
          this._offset += this.count();
          this._data = null;
        }
      }, _a);

      function appendDataSimply(newData) {
        for (var i = 0; i < newData.length; i++) {
          this._data.push(newData[i]);
        }
      }
    }();

    return DefaultDataProvider;
  }();

  var getItemSimply = function (rawData, startIndex, dimsDef, idx) {
    return rawData[idx];
  };

  var rawSourceItemGetterMap = (_a = {}, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = function (rawData, startIndex, dimsDef, idx) {
    return rawData[idx + startIndex];
  }, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = function (rawData, startIndex, dimsDef, idx) {
    idx += startIndex;
    var item = [];
    var data = rawData;

    for (var i = 0; i < data.length; i++) {
      var row = data[i];
      item.push(row ? row[idx] : null);
    }

    return item;
  }, _a[SOURCE_FORMAT_OBJECT_ROWS] = getItemSimply, _a[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, startIndex, dimsDef, idx) {
    var item = [];

    for (var i = 0; i < dimsDef.length; i++) {
      var col = rawData[dimsDef[i].name];
      item.push(col ? col[idx] : null);
    }

    return item;
  }, _a[SOURCE_FORMAT_ORIGINAL] = getItemSimply, _a);

  function getRawSourceItemGetter(sourceFormat, seriesLayoutBy) {
    var method = rawSourceItemGetterMap[getMethodMapKey(sourceFormat, seriesLayoutBy)];

    if (true) {
      assert(method, 'Do not suppport get item on "' + sourceFormat + '", "' + seriesLayoutBy + '".');
    }

    return method;
  }

  var countSimply = function (rawData, startIndex, dimsDef) {
    return rawData.length;
  };

  var rawSourceDataCounterMap = (_b = {}, _b[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = function (rawData, startIndex, dimsDef) {
    return Math.max(0, rawData.length - startIndex);
  }, _b[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = function (rawData, startIndex, dimsDef) {
    var row = rawData[0];
    return row ? Math.max(0, row.length - startIndex) : 0;
  }, _b[SOURCE_FORMAT_OBJECT_ROWS] = countSimply, _b[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, startIndex, dimsDef) {
    var dimName = dimsDef[0].name;
    var col = rawData[dimName];
    return col ? col.length : 0;
  }, _b[SOURCE_FORMAT_ORIGINAL] = countSimply, _b);

  function getRawSourceDataCounter(sourceFormat, seriesLayoutBy) {
    var method = rawSourceDataCounterMap[getMethodMapKey(sourceFormat, seriesLayoutBy)];

    if (true) {
      assert(method, 'Do not suppport count on "' + sourceFormat + '", "' + seriesLayoutBy + '".');
    }

    return method;
  }

  var getRawValueSimply = function (dataItem, dimIndex, dimName) {
    return dimIndex != null ? dataItem[dimIndex] : dataItem;
  };

  var rawSourceValueGetterMap = (_c = {}, _c[SOURCE_FORMAT_ARRAY_ROWS] = getRawValueSimply, _c[SOURCE_FORMAT_OBJECT_ROWS] = function (dataItem, dimIndex, dimName) {
    return dimIndex != null ? dataItem[dimName] : dataItem;
  }, _c[SOURCE_FORMAT_KEYED_COLUMNS] = getRawValueSimply, _c[SOURCE_FORMAT_ORIGINAL] = function (dataItem, dimIndex, dimName) {
    var value = getDataItemValue(dataItem);
    return dimIndex == null || !(value instanceof Array) ? value : value[dimIndex];
  }, _c[SOURCE_FORMAT_TYPED_ARRAY] = getRawValueSimply, _c);

  function getRawSourceValueGetter(sourceFormat) {
    var method = rawSourceValueGetterMap[sourceFormat];

    if (true) {
      assert(method, 'Do not suppport get value on "' + sourceFormat + '".');
    }

    return method;
  }

  function getMethodMapKey(sourceFormat, seriesLayoutBy) {
    return sourceFormat === SOURCE_FORMAT_ARRAY_ROWS ? sourceFormat + '_' + seriesLayoutBy : sourceFormat;
  }

  function retrieveRawValue(data, dataIndex, dim) {
    if (!data) {
      return;
    }

    var dataItem = data.getRawDataItem(dataIndex);

    if (dataItem == null) {
      return;
    }

    var sourceFormat = data.getProvider().getSource().sourceFormat;
    var dimName;
    var dimIndex;
    var dimInfo = data.getDimensionInfo(dim);

    if (dimInfo) {
      dimName = dimInfo.name;
      dimIndex = dimInfo.index;
    }

    return getRawSourceValueGetter(sourceFormat)(dataItem, dimIndex, dimName);
  }

  var DIMENSION_LABEL_REG = /\{@(.+?)\}/g;

  var DataFormatMixin = function () {
    function DataFormatMixin() {}

    DataFormatMixin.prototype.getDataParams = function (dataIndex, dataType) {
      var data = this.getData(dataType);
      var rawValue = this.getRawValue(dataIndex, dataType);
      var rawDataIndex = data.getRawIndex(dataIndex);
      var name = data.getName(dataIndex);
      var itemOpt = data.getRawDataItem(dataIndex);
      var style = data.getItemVisual(dataIndex, 'style');
      var color = style && style[data.getItemVisual(dataIndex, 'drawType') || 'fill'];
      var borderColor = style && style.stroke;
      var mainType = this.mainType;
      var isSeries = mainType === 'series';
      var userOutput = data.userOutput;
      return {
        componentType: mainType,
        componentSubType: this.subType,
        componentIndex: this.componentIndex,
        seriesType: isSeries ? this.subType : null,
        seriesIndex: this.seriesIndex,
        seriesId: isSeries ? this.id : null,
        seriesName: isSeries ? this.name : null,
        name: name,
        dataIndex: rawDataIndex,
        data: itemOpt,
        dataType: dataType,
        value: rawValue,
        color: color,
        borderColor: borderColor,
        dimensionNames: userOutput ? userOutput.dimensionNames : null,
        encode: userOutput ? userOutput.encode : null,
        $vars: ['seriesName', 'name', 'value']
      };
    };

    DataFormatMixin.prototype.getFormattedLabel = function (dataIndex, status, dataType, labelDimIndex, formatter, extendParams) {
      status = status || 'normal';
      var data = this.getData(dataType);
      var params = this.getDataParams(dataIndex, dataType);

      if (extendParams) {
        extend(params, extendParams);
      }

      if (labelDimIndex != null && params.value instanceof Array) {
        params.value = params.value[labelDimIndex];
      }

      if (!formatter) {
        var itemModel = data.getItemModel(dataIndex);
        formatter = itemModel.get(status === 'normal' ? ['label', 'formatter'] : [status, 'label', 'formatter']);
      }

      if (typeof formatter === 'function') {
        params.status = status;
        params.dimensionIndex = labelDimIndex;
        return formatter(params);
      } else if (typeof formatter === 'string') {
        var str = formatTpl(formatter, params);
        return str.replace(DIMENSION_LABEL_REG, function (origin, dim) {
          var len = dim.length;

          if (dim.charAt(0) === '[' && dim.charAt(len - 1) === ']') {
            dim = +dim.slice(1, len - 1);
          }

          return retrieveRawValue(data, dataIndex, dim);
        });
      }
    };

    DataFormatMixin.prototype.getRawValue = function (idx, dataType) {
      return retrieveRawValue(this.getData(dataType), idx);
    };

    DataFormatMixin.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType, renderMode, order) {
      return;
    };

    return DataFormatMixin;
  }();

  function createTask(define) {
    return new Task(define);
  }

  var Task = function () {
    function Task(define) {
      define = define || {};
      this._reset = define.reset;
      this._plan = define.plan;
      this._count = define.count;
      this._onDirty = define.onDirty;
      this._dirty = true;
    }

    Task.prototype.perform = function (performArgs) {
      var upTask = this._upstream;
      var skip = performArgs && performArgs.skip;

      if (this._dirty && upTask) {
        var context = this.context;
        context.data = context.outputData = upTask.context.outputData;
      }

      if (this.__pipeline) {
        this.__pipeline.currentTask = this;
      }

      var planResult;

      if (this._plan && !skip) {
        planResult = this._plan(this.context);
      }

      var lastModBy = normalizeModBy(this._modBy);
      var lastModDataCount = this._modDataCount || 0;
      var modBy = normalizeModBy(performArgs && performArgs.modBy);
      var modDataCount = performArgs && performArgs.modDataCount || 0;

      if (lastModBy !== modBy || lastModDataCount !== modDataCount) {
        planResult = 'reset';
      }

      function normalizeModBy(val) {
        !(val >= 1) && (val = 1);
        return val;
      }

      var forceFirstProgress;

      if (this._dirty || planResult === 'reset') {
        this._dirty = false;
        forceFirstProgress = this._doReset(skip);
      }

      this._modBy = modBy;
      this._modDataCount = modDataCount;
      var step = performArgs && performArgs.step;

      if (upTask) {
        if (true) {
          assert(upTask._outputDueEnd != null);
        }

        this._dueEnd = upTask._outputDueEnd;
      } else {
        if (true) {
          assert(!this._progress || this._count);
        }

        this._dueEnd = this._count ? this._count(this.context) : Infinity;
      }

      if (this._progress) {
        var start = this._dueIndex;
        var end = Math.min(step != null ? this._dueIndex + step : Infinity, this._dueEnd);

        if (!skip && (forceFirstProgress || start < end)) {
          var progress = this._progress;

          if (isArray(progress)) {
            for (var i = 0; i < progress.length; i++) {
              this._doProgress(progress[i], start, end, modBy, modDataCount);
            }
          } else {
            this._doProgress(progress, start, end, modBy, modDataCount);
          }
        }

        this._dueIndex = end;
        var outputDueEnd = this._settedOutputEnd != null ? this._settedOutputEnd : end;

        if (true) {
          assert(outputDueEnd >= this._outputDueEnd);
        }

        this._outputDueEnd = outputDueEnd;
      } else {
        this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null ? this._settedOutputEnd : this._dueEnd;
      }

      return this.unfinished();
    };

    Task.prototype.dirty = function () {
      this._dirty = true;
      this._onDirty && this._onDirty(this.context);
    };

    Task.prototype._doProgress = function (progress, start, end, modBy, modDataCount) {
      iterator.reset(start, end, modBy, modDataCount);
      this._callingProgress = progress;

      this._callingProgress({
        start: start,
        end: end,
        count: end - start,
        next: iterator.next
      }, this.context);
    };

    Task.prototype._doReset = function (skip) {
      this._dueIndex = this._outputDueEnd = this._dueEnd = 0;
      this._settedOutputEnd = null;
      var progress;
      var forceFirstProgress;

      if (!skip && this._reset) {
        progress = this._reset(this.context);

        if (progress && progress.progress) {
          forceFirstProgress = progress.forceFirstProgress;
          progress = progress.progress;
        }

        if (isArray(progress) && !progress.length) {
          progress = null;
        }
      }

      this._progress = progress;
      this._modBy = this._modDataCount = null;
      var downstream = this._downstream;
      downstream && downstream.dirty();
      return forceFirstProgress;
    };

    Task.prototype.unfinished = function () {
      return this._progress && this._dueIndex < this._dueEnd;
    };

    Task.prototype.pipe = function (downTask) {
      if (true) {
        assert(downTask && !downTask._disposed && downTask !== this);
      }

      if (this._downstream !== downTask || this._dirty) {
        this._downstream = downTask;
        downTask._upstream = this;
        downTask.dirty();
      }
    };

    Task.prototype.dispose = function () {
      if (this._disposed) {
        return;
      }

      this._upstream && (this._upstream._downstream = null);
      this._downstream && (this._downstream._upstream = null);
      this._dirty = false;
      this._disposed = true;
    };

    Task.prototype.getUpstream = function () {
      return this._upstream;
    };

    Task.prototype.getDownstream = function () {
      return this._downstream;
    };

    Task.prototype.setOutputEnd = function (end) {
      this._outputDueEnd = this._settedOutputEnd = end;
    };

    return Task;
  }();

  var iterator = function () {
    var end;
    var current;
    var modBy;
    var modDataCount;
    var winCount;
    var it = {
      reset: function (s, e, sStep, sCount) {
        current = s;
        end = e;
        modBy = sStep;
        modDataCount = sCount;
        winCount = Math.ceil(modDataCount / modBy);
        it.next = modBy > 1 && modDataCount > 0 ? modNext : sequentialNext;
      }
    };
    return it;

    function sequentialNext() {
      return current < end ? current++ : null;
    }

    function modNext() {
      var dataIndex = current % winCount * modBy + Math.ceil(current / winCount);
      var result = current >= end ? null : dataIndex < modDataCount ? dataIndex : current;
      current++;
      return result;
    }
  }();

  function parseDataValue(value, opt) {
    var dimType = opt && opt.type;

    if (dimType === 'ordinal') {
      var ordinalMeta = opt && opt.ordinalMeta;
      return ordinalMeta ? ordinalMeta.parseAndCollect(value) : value;
    }

    if (dimType === 'time' && typeof value !== 'number' && value != null && value !== '-') {
      value = +parseDate(value);
    }

    return value == null || value === '' ? NaN : +value;
  }

  var valueParserMap = createHashMap({
    'number': function (val) {
      return parseFloat(val);
    },
    'time': function (val) {
      return +parseDate(val);
    },
    'trim': function (val) {
      return typeof val === 'string' ? trim(val) : val;
    }
  });

  var ExternalSource = function () {
    function ExternalSource() {}

    ExternalSource.prototype.getDimensionInfo = function (dim) {
      return;
    };

    ExternalSource.prototype.getDimensionInfoAll = function () {
      return;
    };

    ExternalSource.prototype.getRawDataItem = function (dataIndex) {
      return;
    };

    ExternalSource.prototype.getRawHeaderItem = function (dataIndex) {
      return;
    };

    ExternalSource.prototype.count = function () {
      return;
    };

    ExternalSource.prototype.retrieveItemValue = function (rawItem, dimIndex) {
      return;
    };

    ExternalSource.prototype.convertDataValue = function (rawVal, dimInfo) {
      return parseDataValue(rawVal, dimInfo);
    };

    return ExternalSource;
  }();

  function createExternalSource(data, sourceFormat, dimsDef, sourceHeaderCount) {
    var extSource = new ExternalSource();
    extSource.data = data;
    extSource.sourceFormat = sourceFormat;
    extSource.sourceHeaderCount = sourceHeaderCount;
    var dimensions = [];
    var dimsByName = {};
    each(dimsDef, function (dimDef, idx) {
      var name = dimDef.name;
      var dimDefExt = {
        index: idx,
        name: name,
        displayName: dimDef.displayName
      };
      dimensions.push(dimDefExt);

      if (name != null) {
        assert(!hasOwn(dimsByName, name), 'dimension name "' + name + '" duplicated.');
        dimsByName[name] = dimDefExt;
      }
    });
    var rawItemGetter = getRawSourceItemGetter(sourceFormat, SERIES_LAYOUT_BY_COLUMN);
    extSource.getRawDataItem = bind(rawItemGetter, null, data, sourceHeaderCount, dimensions);

    extSource.getRawHeaderItem = function (dataIndex) {
      if (dataIndex < sourceHeaderCount) {
        return rawItemGetter(data, 0, dimensions, dataIndex);
      }
    };

    var rawCounter = getRawSourceDataCounter(sourceFormat, SERIES_LAYOUT_BY_COLUMN);
    extSource.count = bind(rawCounter, null, data, sourceHeaderCount, dimensions);
    var rawValueGetter = getRawSourceValueGetter(sourceFormat);

    extSource.retrieveItemValue = function (rawItem, dimIndex) {
      if (rawItem == null) {
        return;
      }

      var dimDef = dimensions[dimIndex];

      if (dimDef) {
        return rawValueGetter(rawItem, dimIndex, dimDef.name);
      }
    };

    extSource.getDimensionInfo = bind(getDimensionInfo, null, dimensions, dimsByName);
    extSource.getDimensionInfoAll = bind(getDimensionInfoAll, null, dimensions);
    return extSource;
  }

  function getDimensionInfo(dimensions, dimsByName, dim) {
    if (dim == null) {
      return;
    }

    if (typeof dim === 'number' || !isNaN(dim) && !hasOwn(dimsByName, dim)) {
      return dimensions[dim];
    } else if (hasOwn(dimsByName, dim)) {
      return dimsByName[dim];
    }
  }

  function getDimensionInfoAll(dimensions) {
    return dimensions;
  }

  var externalTransformMap = createHashMap();

  function registerExternalTransform(externalTransform) {
    externalTransform = clone(externalTransform);
    var type = externalTransform.type;
    assert(type, 'Must have a `type` when `registerTransform`.');
    var typeParsed = type.split(':');
    assert(typeParsed.length === 2, 'Name must include namespace like "ns:regression".');

    if (typeParsed[0] === 'echarts') {
      type = typeParsed[1];
    }

    externalTransformMap.set(type, externalTransform);
  }

  function applyDataTransform(rawTransOption, sourceList, infoForPrint) {
    var pipedTransOption = normalizeToArray(rawTransOption);

    for (var i = 0, len = pipedTransOption.length; i < len; i++) {
      var transOption = pipedTransOption[i];
      var isFinal = i === len - 1;
      sourceList = applySingleDataTransform(transOption, sourceList, infoForPrint, isFinal);

      if (!isFinal) {
        sourceList.length = Math.max(sourceList.length, 1);
      }
    }

    return sourceList;
  }

  function applySingleDataTransform(rawTransOption, upSourceList, infoForPrint, isFinal) {
    assert(upSourceList.length, 'Must have at least one upstream dataset.');
    var transOption = rawTransOption;
    var transType = transOption.type;
    var externalTransform = externalTransformMap.get(transType);
    assert(externalTransform, 'Can not find transform on type "' + transType + '".');
    var sourceList = map(upSourceList, function (source) {
      return createExternalSource(source.data, source.sourceFormat, source.dimensionsDefine, source.startIndex);
    });
    var resultList = normalizeToArray(externalTransform.transform({
      source: sourceList[0],
      sourceList: sourceList,
      config: clone(transOption.config)
    }));

    if (true) {
      if (isFinal && transOption.print) {
        var printStrArr = map(resultList, function (extSource) {
          return ['--- datasetIndex: ' + infoForPrint.datasetIndex + '---', '- transform result data:', makePrintable(extSource.data), '- transform result dimensions:', makePrintable(extSource.dimensions), '- transform result sourceHeader: ' + extSource.sourceHeader, '------'].join('\n');
        }).join('\n');
        consoleLog(printStrArr);
      }
    }

    return map(resultList, function (result) {
      assert(isObject(result), 'A transform should not return some empty results.');
      assert(isObject(result.data) || isArrayLike(result.data), 'Result data should be object or array in data transform.');
      var resultMetaRawOption = inheritSourceMetaRawOption({
        parent: upSourceList[0].metaRawOption,
        thisNew: {
          seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,
          sourceHeader: result.sourceHeader,
          dimensions: result.dimensions
        }
      });
      return createSource(result.data, resultMetaRawOption, null, null);
    });
  }

  var SourceManager = function () {
    function SourceManager(sourceHost) {
      this._sourceList = [];
      this._upstreamSignList = [];
      this._versionSignBase = 0;
      this._sourceHost = sourceHost;
    }

    SourceManager.prototype.dirty = function () {
      this._setLocalSource([], []);
    };

    SourceManager.prototype._setLocalSource = function (sourceList, upstreamSignList) {
      this._sourceList = sourceList;
      this._upstreamSignList = upstreamSignList;
      this._versionSignBase++;

      if (this._versionSignBase > 9e10) {
        this._versionSignBase = 0;
      }
    };

    SourceManager.prototype._getVersionSign = function () {
      return this._sourceHost.uid + '_' + this._versionSignBase;
    };

    SourceManager.prototype.prepareSource = function () {
      if (this._isDirty()) {
        this._createSource();
      }
    };

    SourceManager.prototype._createSource = function () {
      this._setLocalSource([], []);

      var sourceHost = this._sourceHost;

      var upSourceMgrList = this._getUpstreamSourceManagers();

      var hasUpstream = !!upSourceMgrList.length;
      var resultSourceList;
      var upstreamSignList;

      if (isSeries(sourceHost)) {
        var seriesModel = sourceHost;
        var data = void 0;
        var sourceFormat = void 0;
        var upSource = void 0;

        if (hasUpstream) {
          var upSourceMgr = upSourceMgrList[0];
          upSourceMgr.prepareSource();
          upSource = upSourceMgr.getSource();
          data = upSource.data;
          sourceFormat = upSource.sourceFormat;
          upstreamSignList = [upSourceMgr._getVersionSign()];
        } else {
          data = seriesModel.get('data', true);
          sourceFormat = isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL;
          upstreamSignList = [];
        }

        var thisMetaRawOption = inheritSourceMetaRawOption({
          parent: upSource ? upSource.metaRawOption : null,
          thisNew: this._createSourceMetaRawOption()
        });
        resultSourceList = [createSource(data, thisMetaRawOption, sourceFormat, seriesModel.get('encode', true))];
      } else {
        var datasetModel = sourceHost;

        if (hasUpstream) {
          var result = this._applyTransform(upSourceMgrList);

          resultSourceList = result.sourceList;
          upstreamSignList = result.upstreamSignList;
        } else {
          var sourceData = datasetModel.get('source', true);
          resultSourceList = [createSource(sourceData, this._createSourceMetaRawOption(), null, null)];
          upstreamSignList = [];
        }
      }

      if (true) {
        assert(resultSourceList && upstreamSignList);
      }

      this._setLocalSource(resultSourceList, upstreamSignList);
    };

    SourceManager.prototype._applyTransform = function (upMgrList) {
      var datasetModel = this._sourceHost;
      var transformOption = datasetModel.get('transform', true);
      var fromTransformResult = datasetModel.get('fromTransformResult', true);
      var sourceList;
      var upstreamSignList;

      if (transformOption) {
        var upSourceList_1 = [];
        upstreamSignList = [];
        each(upMgrList, function (upMgr) {
          upMgr.prepareSource();
          upSourceList_1.push(upMgr.getSource());
          upstreamSignList.push(upMgr._getVersionSign());
        });
        sourceList = applyDataTransform(transformOption, upSourceList_1, {
          datasetIndex: datasetModel.componentIndex
        });
      } else if (fromTransformResult != null) {
        if (upMgrList.length !== 1) {
          var errMsg = '';

          if (true) {
            errMsg = 'When using `fromTransformResult`, there should be only one upstream dataset';
          }

          doThrow(errMsg);
        }

        var upMgr = upMgrList[0];
        upMgr.prepareSource();
        var upSource = upMgr.getSource(fromTransformResult);
        upstreamSignList = [upMgr._getVersionSign()];
        sourceList = [cloneSourceShallow(upSource)];
      }

      return {
        sourceList: sourceList,
        upstreamSignList: upstreamSignList
      };
    };

    SourceManager.prototype._isDirty = function () {
      var sourceList = this._sourceList;

      if (!sourceList.length) {
        return true;
      }

      var upSourceMgrList = this._getUpstreamSourceManagers();

      for (var i = 0; i < upSourceMgrList.length; i++) {
        var upSrcMgr = upSourceMgrList[i];

        if (upSrcMgr._isDirty() || this._upstreamSignList[i] !== upSrcMgr._getVersionSign()) {
          return true;
        }
      }
    };

    SourceManager.prototype.getSource = function (sourceIndex) {
      return this._sourceList[sourceIndex || 0];
    };

    SourceManager.prototype._getUpstreamSourceManagers = function () {
      var sourceHost = this._sourceHost;

      if (isSeries(sourceHost)) {
        var datasetModel = querySeriesUpstreamDatasetModel(sourceHost);
        return !datasetModel ? [] : [datasetModel.getSourceManager()];
      } else {
        return map(queryDatasetUpstreamDatasetModels(sourceHost), function (datasetModel) {
          return datasetModel.getSourceManager();
        });
      }
    };

    SourceManager.prototype._createSourceMetaRawOption = function () {
      var sourceHost = this._sourceHost;
      var seriesLayoutBy;
      var sourceHeader;
      var dimensions;

      if (isSeries(sourceHost)) {
        seriesLayoutBy = sourceHost.get('seriesLayoutBy', true);
        sourceHeader = sourceHost.get('sourceHeader', true);
        dimensions = sourceHost.get('dimensions', true);
      } else if (!this._getUpstreamSourceManagers().length) {
        var model = sourceHost;
        seriesLayoutBy = model.get('seriesLayoutBy', true);
        sourceHeader = model.get('sourceHeader', true);
        dimensions = model.get('dimensions', true);
      }

      return {
        seriesLayoutBy: seriesLayoutBy,
        sourceHeader: sourceHeader,
        dimensions: dimensions
      };
    };

    return SourceManager;
  }();

  function disableTransformOptionMerge(datasetModel) {
    var transformOption = datasetModel.option.transform;
    transformOption && setAsPrimitive(datasetModel.option.transform);
  }

  function isSeries(sourceHost) {
    return sourceHost.mainType === 'series';
  }

  function doThrow(errMsg) {
    throw new Error(errMsg);
  }

  var inner$2 = makeInner();

  function getSelectionKey(data, dataIndex) {
    return data.getName(dataIndex) || data.getId(dataIndex);
  }

  var SeriesModel = function (_super) {
    __extends(SeriesModel, _super);

    function SeriesModel() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this._selectedDataIndicesMap = {};
      return _this;
    }

    SeriesModel.prototype.init = function (option, parentModel, ecModel) {
      this.seriesIndex = this.componentIndex;
      this.dataTask = createTask({
        count: dataTaskCount,
        reset: dataTaskReset
      });
      this.dataTask.context = {
        model: this
      };
      this.mergeDefaultAndTheme(option, ecModel);
      var sourceManager = inner$2(this).sourceManager = new SourceManager(this);
      sourceManager.prepareSource();
      var data = this.getInitialData(option, ecModel);
      wrapData(data, this);
      this.dataTask.context.data = data;

      if (true) {
        assert(data, 'getInitialData returned invalid data.');
      }

      inner$2(this).dataBeforeProcessed = data;
      autoSeriesName(this);

      this._initSelectedMapFromData(data);
    };

    SeriesModel.prototype.mergeDefaultAndTheme = function (option, ecModel) {
      var layoutMode = fetchLayoutMode(this);
      var inputPositionParams = layoutMode ? getLayoutParams(option) : {};
      var themeSubType = this.subType;

      if (ComponentModel.hasClass(themeSubType)) {
        themeSubType += 'Series';
      }

      merge(option, ecModel.getTheme().get(this.subType));
      merge(option, this.getDefaultOption());
      defaultEmphasis(option, 'label', ['show']);
      this.fillDataTextStyle(option.data);

      if (layoutMode) {
        mergeLayoutParam(option, inputPositionParams, layoutMode);
      }
    };

    SeriesModel.prototype.mergeOption = function (newSeriesOption, ecModel) {
      newSeriesOption = merge(this.option, newSeriesOption, true);
      this.fillDataTextStyle(newSeriesOption.data);
      var layoutMode = fetchLayoutMode(this);

      if (layoutMode) {
        mergeLayoutParam(this.option, newSeriesOption, layoutMode);
      }

      var sourceManager = inner$2(this).sourceManager;
      sourceManager.dirty();
      sourceManager.prepareSource();
      var data = this.getInitialData(newSeriesOption, ecModel);
      wrapData(data, this);
      this.dataTask.dirty();
      this.dataTask.context.data = data;
      inner$2(this).dataBeforeProcessed = data;
      autoSeriesName(this);

      this._initSelectedMapFromData(data);
    };

    SeriesModel.prototype.fillDataTextStyle = function (data) {
      if (data && !isTypedArray(data)) {
        var props = ['show'];

        for (var i = 0; i < data.length; i++) {
          if (data[i] && data[i].label) {
            defaultEmphasis(data[i], 'label', props);
          }
        }
      }
    };

    SeriesModel.prototype.getInitialData = function (option, ecModel) {
      return;
    };

    SeriesModel.prototype.appendData = function (params) {
      var data = this.getRawData();
      data.appendData(params.data);
    };

    SeriesModel.prototype.getData = function (dataType) {
      var task = getCurrentTask(this);

      if (task) {
        var data = task.context.data;
        return dataType == null ? data : data.getLinkedData(dataType);
      } else {
        return inner$2(this).data;
      }
    };

    SeriesModel.prototype.getAllData = function () {
      var mainData = this.getData();
      return mainData && mainData.getLinkedDataAll ? mainData.getLinkedDataAll() : [{
        data: mainData
      }];
    };

    SeriesModel.prototype.setData = function (data) {
      var task = getCurrentTask(this);

      if (task) {
        var context = task.context;
        context.outputData = data;

        if (task !== this.dataTask) {
          context.data = data;
        }
      }

      inner$2(this).data = data;
    };

    SeriesModel.prototype.getSource = function () {
      return inner$2(this).sourceManager.getSource();
    };

    SeriesModel.prototype.getRawData = function () {
      return inner$2(this).dataBeforeProcessed;
    };

    SeriesModel.prototype.getBaseAxis = function () {
      var coordSys = this.coordinateSystem;
      return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();
    };

    SeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType, renderMode) {
      var series = this;
      renderMode = renderMode || 'html';
      var newLine = renderMode === 'html' ? '' : '\n';
      var isRichText = renderMode === 'richText';
      var markers = {};
      var markerId = 0;

      function formatArrayValue(value) {
        var vertially = reduce(value, function (vertially, val, idx) {
          var dimItem = data.getDimensionInfo(idx);
          return vertially |= dimItem && dimItem.tooltip !== false && dimItem.displayName != null;
        }, 0);
        var result = [];
        tooltipDims.length ? each(tooltipDims, function (dim) {
          setEachItem(retrieveRawValue(data, dataIndex, dim), dim);
        }) : each(value, setEachItem);

        function setEachItem(val, dim) {
          var dimInfo = data.getDimensionInfo(dim);

          if (!dimInfo || dimInfo.otherDims.tooltip === false) {
            return;
          }

          var dimType = dimInfo.type;
          var markName = 'sub' + series.seriesIndex + 'at' + markerId;
          var dimHead = getTooltipMarker({
            color: colorStr,
            type: 'subItem',
            renderMode: renderMode,
            markerId: markName
          });
          var dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content;
          var valStr = (vertially ? '<span style="font-size:12px;color:#6e7079;">' + dimHeadStr + encodeHTML(dimInfo.displayName || '-') + '</span>' : '') + '<span style="float:right;margin-left:20px;color:#000;font-weight:900">' + encodeHTML(dimType === 'ordinal' ? val + '' : dimType === 'time' ? multipleSeries ? '' : formatTime('yyyy/MM/dd hh:mm:ss', val) : addCommas(val)) + '</span>';
          valStr && result.push("<div style=\"margin: 11px 0 0;line-height:1;\">" + valStr + "</div>");

          if (isRichText) {
            markers[markName] = colorStr;
            ++markerId;
          }
        }

        var newLine = vertially ? isRichText ? '\n' : '' : '';
        var content = newLine + result.join(newLine || '');
        return {
          renderMode: renderMode,
          content: content,
          style: markers
        };
      }

      function formatSingleValue(val) {
        return {
          renderMode: renderMode,
          content: encodeHTML(addCommas(val)),
          style: markers
        };
      }

      var data = this.getData();
      var tooltipDims = data.mapDimensionsAll('defaultedTooltip');
      var tooltipDimLen = tooltipDims.length;
      var value = this.getRawValue(dataIndex);
      var isValueArr = isArray(value);
      var style = data.getItemVisual(dataIndex, 'style');
      var color = style[this.visualDrawType];
      var colorStr;

      if (isString(color)) {
        colorStr = color;
      } else if (color && color.colorStops) {
        colorStr = (color.colorStops[0] || {}).color;
      }

      colorStr = colorStr || 'transparent';
      var formattedValue = tooltipDimLen > 1 || isValueArr && !tooltipDimLen ? formatArrayValue(value) : tooltipDimLen ? formatSingleValue(retrieveRawValue(data, dataIndex, tooltipDims[0])) : formatSingleValue(isValueArr ? value[0] : value);
      var content = isRichText ? formattedValue.content : tooltipDimLen > 1 || isValueArr && !tooltipDimLen ? '<div>' + formattedValue.content + '</div>' : '<span style="float:right;margin-left:20px;color:#464646;font-weight:bold">' + formattedValue.content + '</span>';
      var markName = series.seriesIndex + 'at' + markerId;
      var colorEl = getTooltipMarker({
        color: colorStr,
        type: 'item',
        renderMode: renderMode,
        markerId: markName
      });
      markers[markName] = colorStr;
      ++markerId;
      var name = data.getName(dataIndex);
      var seriesName = this.name;

      if (!isNameSpecified(this)) {
        seriesName = '';
      }

      seriesName = seriesName ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ' ') : '';
      colorStr = isString(colorEl) ? colorEl : colorEl.content;
      var html = '';

      if (!isRichText) {
        seriesName = seriesName ? !multipleSeries ? "<div style=\"font-size:12px;color:#6e7079;line-height:1;margin-top:-4px;\">" + seriesName + "</div>" : "<span style=\"font-size:12px;color:#6e7079;line-height:1\">" + seriesName + "</span>" : '';
        html = !multipleSeries ? seriesName + ("<div style=\"margin: " + (seriesName ? 8 : 0) + "px 0 0;line-height:1\">") + colorStr + (name ? "<span style=\"font-size:12px;color:#6e7079;\">" + encodeHTML(name) + "</span>" + content : content) + '</div>' : "<div style=\"margin: 11px 0 0;line-height:1;\">" + colorStr + seriesName + content + "</div>";
      } else {
        html = !multipleSeries ? seriesName + (seriesName ? '\n' : '') + '' + colorStr + (name ? encodeHTML(name) + ": " + content : content) + '' : "" + colorStr + seriesName + ": " + content;
      }

      return {
        html: html,
        markers: markers
      };
    };

    SeriesModel.prototype.isAnimationEnabled = function () {
      if (env.node) {
        return false;
      }

      var animationEnabled = this.getShallow('animation');

      if (animationEnabled) {
        if (this.getData().count() > this.getShallow('animationThreshold')) {
          animationEnabled = false;
        }
      }

      return !!animationEnabled;
    };

    SeriesModel.prototype.restoreData = function () {
      this.dataTask.dirty();
    };

    SeriesModel.prototype.getColorFromPalette = function (name, scope, requestColorNum) {
      var ecModel = this.ecModel;
      var color = ColorPaletteMixin.prototype.getColorFromPalette.call(this, name, scope, requestColorNum);

      if (!color) {
        color = ecModel.getColorFromPalette(name, scope, requestColorNum);
      }

      return color;
    };

    SeriesModel.prototype.coordDimToDataDim = function (coordDim) {
      return this.getRawData().mapDimensionsAll(coordDim);
    };

    SeriesModel.prototype.getProgressive = function () {
      return this.get('progressive');
    };

    SeriesModel.prototype.getProgressiveThreshold = function () {
      return this.get('progressiveThreshold');
    };

    SeriesModel.prototype.select = function (innerDataIndices, dataType) {
      this._innerSelect(this.getData(dataType), innerDataIndices);
    };

    SeriesModel.prototype.unselect = function (innerDataIndices, dataType) {
      var selectedMap = this.option.selectedMap;

      if (!selectedMap) {
        return;
      }

      var data = this.getData(dataType);

      for (var i = 0; i < innerDataIndices.length; i++) {
        var dataIndex = innerDataIndices[i];
        var nameOrId = getSelectionKey(data, dataIndex);
        selectedMap[nameOrId] = false;
        this._selectedDataIndicesMap[nameOrId] = -1;
      }
    };

    SeriesModel.prototype.toggleSelect = function (innerDataIndices, dataType) {
      var tmpArr = [];

      for (var i = 0; i < innerDataIndices.length; i++) {
        tmpArr[0] = innerDataIndices[i];
        this.isSelected(innerDataIndices[i], dataType) ? this.unselect(tmpArr, dataType) : this.select(tmpArr, dataType);
      }
    };

    SeriesModel.prototype.getSelectedDataIndices = function () {
      var selectedDataIndicesMap = this._selectedDataIndicesMap;
      var nameOrIds = keys(selectedDataIndicesMap);
      var dataIndices = [];

      for (var i = 0; i < nameOrIds.length; i++) {
        var dataIndex = selectedDataIndicesMap[nameOrIds[i]];

        if (dataIndex >= 0) {
          dataIndices.push(dataIndex);
        }
      }

      return dataIndices;
    };

    SeriesModel.prototype.isSelected = function (dataIndex, dataType) {
      var selectedMap = this.option.selectedMap;

      if (!selectedMap) {
        return false;
      }

      var data = this.getData(dataType);
      var nameOrId = getSelectionKey(data, dataIndex);
      return selectedMap[nameOrId] || false;
    };

    SeriesModel.prototype._innerSelect = function (data, innerDataIndices) {
      var _a, _b;

      var selectedMode = this.option.selectedMode;
      var len = innerDataIndices.length;

      if (!selectedMode || !len) {
        return;
      }

      if (selectedMode === 'multiple') {
        var selectedMap = this.option.selectedMap || (this.option.selectedMap = {});

        for (var i = 0; i < len; i++) {
          var dataIndex = innerDataIndices[i];
          var nameOrId = getSelectionKey(data, dataIndex);
          selectedMap[nameOrId] = true;
          this._selectedDataIndicesMap[nameOrId] = data.getRawIndex(dataIndex);
        }
      } else if (selectedMode === 'single' || selectedMode === true) {
        var lastDataIndex = innerDataIndices[len - 1];
        var nameOrId = getSelectionKey(data, lastDataIndex);
        this.option.selectedMap = (_a = {}, _a[nameOrId] = true, _a);
        this._selectedDataIndicesMap = (_b = {}, _b[nameOrId] = data.getRawIndex(lastDataIndex), _b);
      }
    };

    SeriesModel.prototype._initSelectedMapFromData = function (data) {
      if (this.option.selectedMap) {
        return;
      }

      var dataIndices = [];

      if (data.hasItemOption) {
        data.each(function (idx) {
          var rawItem = data.getRawDataItem(idx);

          if (typeof rawItem === 'object' && rawItem.selected) {
            dataIndices.push(idx);
          }
        });
      }

      if (dataIndices.length > 0) {
        this._innerSelect(data, dataIndices);
      }
    };

    SeriesModel.registerClass = function (clz) {
      return ComponentModel.registerClass(clz);
    };

    SeriesModel.protoInitialize = function () {
      var proto = SeriesModel.prototype;
      proto.type = 'series.__base__';
      proto.seriesIndex = 0;
      proto.useColorPaletteOnData = false;
      proto.ignoreStyleOnData = false;
      proto.hasSymbolVisual = false;
      proto.defaultSymbol = 'circle';
      proto.visualStyleAccessPath = 'itemStyle';
      proto.visualDrawType = 'fill';
    }();

    return SeriesModel;
  }(ComponentModel);

  mixin(SeriesModel, DataFormatMixin);
  mixin(SeriesModel, ColorPaletteMixin);
  mountExtend(SeriesModel, ComponentModel);

  function autoSeriesName(seriesModel) {
    var name = seriesModel.name;

    if (!isNameSpecified(seriesModel)) {
      seriesModel.name = getSeriesAutoName(seriesModel) || name;
    }
  }

  function getSeriesAutoName(seriesModel) {
    var data = seriesModel.getRawData();
    var dataDims = data.mapDimensionsAll('seriesName');
    var nameArr = [];
    each(dataDims, function (dataDim) {
      var dimInfo = data.getDimensionInfo(dataDim);
      dimInfo.displayName && nameArr.push(dimInfo.displayName);
    });
    return nameArr.join(' ');
  }

  function dataTaskCount(context) {
    return context.model.getRawData().count();
  }

  function dataTaskReset(context) {
    var seriesModel = context.model;
    seriesModel.setData(seriesModel.getRawData().cloneShallow());
    return dataTaskProgress;
  }

  function dataTaskProgress(param, context) {
    if (context.outputData && param.end > context.outputData.count()) {
      context.model.getRawData().cloneShallow(context.outputData);
    }
  }

  function wrapData(data, seriesModel) {
    each(data.CHANGABLE_METHODS, function (methodName) {
      data.wrapMethod(methodName, curry(onDataSelfChange, seriesModel));
    });
  }

  function onDataSelfChange(seriesModel) {
    var task = getCurrentTask(seriesModel);

    if (task) {
      task.setOutputEnd(this.count());
    }
  }

  function getCurrentTask(seriesModel) {
    var scheduler = (seriesModel.ecModel || {}).scheduler;
    var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid);

    if (pipeline) {
      var task = pipeline.currentTask;

      if (task) {
        var agentStubMap = task.agentStubMap;

        if (agentStubMap) {
          task = agentStubMap.get(seriesModel.uid);
        }
      }

      return task;
    }
  }

  var ComponentView = function () {
    function ComponentView() {
      this.group = new Group();
      this.uid = getUID('viewComponent');
    }

    ComponentView.prototype.init = function (ecModel, api) {};

    ComponentView.prototype.render = function (model, ecModel, api, payload) {};

    ComponentView.prototype.dispose = function (ecModel, api) {};

    ComponentView.prototype.updateView = function (model, ecModel, api, payload) {};

    ComponentView.prototype.updateLayout = function (model, ecModel, api, payload) {};

    ComponentView.prototype.updateVisual = function (model, ecModel, api, payload) {};

    ComponentView.prototype.blurSeries = function (seriesModels, ecModel) {};

    return ComponentView;
  }();

  enableClassExtend(ComponentView);
  enableClassManagement(ComponentView, {
    registerWhenExtend: true
  });

  function createRenderPlanner() {
    var inner = makeInner();
    return function (seriesModel) {
      var fields = inner(seriesModel);
      var pipelineContext = seriesModel.pipelineContext;
      var originalLarge = fields.large;
      var originalProgressive = fields.progressiveRender;
      var large = fields.large = pipelineContext && pipelineContext.large;
      var progressive = fields.progressiveRender = pipelineContext && pipelineContext.progressiveRender;
      return !!(originalLarge ^ large || originalProgressive ^ progressive) && 'reset';
    };
  }

  var inner$3 = makeInner();
  var renderPlanner = createRenderPlanner();

  var ChartView = function () {
    function ChartView() {
      this.group = new Group();
      this.uid = getUID('viewChart');
      this.renderTask = createTask({
        plan: renderTaskPlan,
        reset: renderTaskReset
      });
      this.renderTask.context = {
        view: this
      };
    }

    ChartView.prototype.init = function (ecModel, api) {};

    ChartView.prototype.render = function (seriesModel, ecModel, api, payload) {};

    ChartView.prototype.highlight = function (seriesModel, ecModel, api, payload) {
      toggleHighlight(seriesModel.getData(), payload, 'emphasis');
    };

    ChartView.prototype.downplay = function (seriesModel, ecModel, api, payload) {
      toggleHighlight(seriesModel.getData(), payload, 'normal');
    };

    ChartView.prototype.remove = function (ecModel, api) {
      this.group.removeAll();
    };

    ChartView.prototype.dispose = function (ecModel, api) {};

    ChartView.prototype.updateView = function (seriesModel, ecModel, api, payload) {
      this.render(seriesModel, ecModel, api, payload);
    };

    ChartView.prototype.updateLayout = function (seriesModel, ecModel, api, payload) {
      this.render(seriesModel, ecModel, api, payload);
    };

    ChartView.prototype.updateVisual = function (seriesModel, ecModel, api, payload) {
      this.render(seriesModel, ecModel, api, payload);
    };

    ChartView.markUpdateMethod = function (payload, methodName) {
      inner$3(payload).updateMethod = methodName;
    };

    ChartView.protoInitialize = function () {
      var proto = ChartView.prototype;
      proto.type = 'chart';
    }();

    return ChartView;
  }();

  function elSetState(el, state, highlightDigit) {
    if (el) {
      (state === 'emphasis' ? enterEmphasis : leaveEmphasis)(el, highlightDigit);
    }
  }

  function toggleHighlight(data, payload, state) {
    var dataIndex = queryDataIndex(data, payload);
    var highlightDigit = payload && payload.highlightKey != null ? getHighlightDigit(payload.highlightKey) : null;

    if (dataIndex != null) {
      each(normalizeToArray(dataIndex), function (dataIdx) {
        elSetState(data.getItemGraphicEl(dataIdx), state, highlightDigit);
      });
    } else {
      data.eachItemGraphicEl(function (el) {
        elSetState(el, state, highlightDigit);
      });
    }
  }

  enableClassExtend(ChartView, ['dispose']);
  enableClassManagement(ChartView, {
    registerWhenExtend: true
  });

  function renderTaskPlan(context) {
    return renderPlanner(context.model);
  }

  function renderTaskReset(context) {
    var seriesModel = context.model;
    var ecModel = context.ecModel;
    var api = context.api;
    var payload = context.payload;
    var progressiveRender = seriesModel.pipelineContext.progressiveRender;
    var view = context.view;
    var updateMethod = payload && inner$3(payload).updateMethod;
    var methodName = progressiveRender ? 'incrementalPrepareRender' : updateMethod && view[updateMethod] ? updateMethod : 'render';

    if (methodName !== 'render') {
      view[methodName](seriesModel, ecModel, api, payload);
    }

    return progressMethodMap[methodName];
  }

  var progressMethodMap = {
    incrementalPrepareRender: {
      progress: function (params, context) {
        context.view.incrementalRender(params, context.model, context.ecModel, context.api, context.payload);
      }
    },
    render: {
      forceFirstProgress: true,
      progress: function (params, context) {
        context.view.render(context.model, context.ecModel, context.api, context.payload);
      }
    }
  };

  function throttle(fn, delay, debounce) {
    var currCall;
    var lastCall = 0;
    var lastExec = 0;
    var timer = null;
    var diff;
    var scope;
    var args;
    var debounceNextCall;
    delay = delay || 0;

    function exec() {
      lastExec = new Date().getTime();
      timer = null;
      fn.apply(scope, args || []);
    }

    var cb = function () {
      var cbArgs = [];

      for (var _i = 0; _i < arguments.length; _i++) {
        cbArgs[_i] = arguments[_i];
      }

      currCall = new Date().getTime();
      scope = this;
      args = cbArgs;
      var thisDelay = debounceNextCall || delay;
      var thisDebounce = debounceNextCall || debounce;
      debounceNextCall = null;
      diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;
      clearTimeout(timer);

      if (thisDebounce) {
        timer = setTimeout(exec, thisDelay);
      } else {
        if (diff >= 0) {
          exec();
        } else {
          timer = setTimeout(exec, -diff);
        }
      }

      lastCall = currCall;
    };

    cb.clear = function () {
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
    };

    cb.debounceNextCall = function (debounceDelay) {
      debounceNextCall = debounceDelay;
    };

    return cb;
  }

  var inner$4 = makeInner();
  var defaultStyleMappers = {
    itemStyle: makeStyleMapper(ITEM_STYLE_KEY_MAP, true),
    lineStyle: makeStyleMapper(LINE_STYLE_KEY_MAP, true)
  };
  var defaultColorKey = {
    lineStyle: 'stroke',
    itemStyle: 'fill'
  };

  function getStyleMapper(seriesModel, stylePath) {
    var styleMapper = seriesModel.visualStyleMapper || defaultStyleMappers[stylePath];

    if (!styleMapper) {
      console.warn("Unkown style type '" + stylePath + "'.");
      return defaultStyleMappers.itemStyle;
    }

    return styleMapper;
  }

  function getDefaultColorKey(seriesModel, stylePath) {
    var colorKey = seriesModel.visualDrawType || defaultColorKey[stylePath];

    if (!colorKey) {
      console.warn("Unkown style type '" + stylePath + "'.");
      return 'fill';
    }

    return colorKey;
  }

  var seriesStyleTask = {
    createOnAllSeries: true,
    performRawSeries: true,
    reset: function (seriesModel, ecModel) {
      var data = seriesModel.getData();
      var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle';
      var styleModel = seriesModel.getModel(stylePath);
      var getStyle = getStyleMapper(seriesModel, stylePath);
      var globalStyle = getStyle(styleModel);
      var colorKey = getDefaultColorKey(seriesModel, stylePath);
      var color = globalStyle[colorKey];
      var colorCallback = isFunction(color) ? color : null;

      if (!globalStyle[colorKey] || colorCallback) {
        globalStyle[colorKey] = seriesModel.getColorFromPalette(seriesModel.name, null, ecModel.getSeriesCount());
        data.setVisual('colorFromPalette', true);
      }

      data.setVisual('style', globalStyle);
      data.setVisual('drawType', colorKey);

      if (!ecModel.isSeriesFiltered(seriesModel) && colorCallback) {
        data.setVisual('colorFromPalette', false);
        return {
          dataEach: function (data, idx) {
            var dataParams = seriesModel.getDataParams(idx);
            var itemStyle = extend({}, globalStyle);
            itemStyle[colorKey] = colorCallback(dataParams);
            data.setItemVisual(idx, 'style', itemStyle);
          }
        };
      }
    }
  };
  var sharedModel = new Model();
  var dataStyleTask = {
    createOnAllSeries: true,
    performRawSeries: true,
    reset: function (seriesModel, ecModel) {
      if (seriesModel.ignoreStyleOnData || ecModel.isSeriesFiltered(seriesModel)) {
        return;
      }

      var data = seriesModel.getData();
      var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle';
      var getStyle = getStyleMapper(seriesModel, stylePath);
      var colorKey = data.getVisual('drawType');
      return {
        dataEach: data.hasItemOption ? function (data, idx) {
          var rawItem = data.getRawDataItem(idx);

          if (rawItem && rawItem[stylePath]) {
            sharedModel.option = rawItem[stylePath];
            var style = getStyle(sharedModel);
            var existsStyle = data.ensureUniqueItemVisual(idx, 'style');
            extend(existsStyle, style);

            if (colorKey in style) {
              data.setItemVisual(idx, 'colorFromPalette', false);
            }
          }
        } : null
      };
    }
  };
  var dataColorPaletteTask = {
    createOnAllSeries: true,
    performRawSeries: true,
    overallReset: function (ecModel) {
      var paletteScopeGroupByType = createHashMap();
      ecModel.eachSeries(function (seriesModel) {
        if (!seriesModel.useColorPaletteOnData) {
          return;
        }

        var colorScope = paletteScopeGroupByType.get(seriesModel.type);

        if (!colorScope) {
          colorScope = {};
          paletteScopeGroupByType.set(seriesModel.type, colorScope);
        }

        inner$4(seriesModel).scope = colorScope;
      });
      ecModel.eachSeries(function (seriesModel) {
        if (!seriesModel.useColorPaletteOnData || ecModel.isSeriesFiltered(seriesModel)) {
          return;
        }

        var dataAll = seriesModel.getRawData();
        var idxMap = {};
        var data = seriesModel.getData();
        var colorScope = inner$4(seriesModel).scope;
        var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle';
        var colorKey = getDefaultColorKey(seriesModel, stylePath);
        data.each(function (idx) {
          var rawIdx = data.getRawIndex(idx);
          idxMap[rawIdx] = idx;
        });
        dataAll.each(function (rawIdx) {
          var idx = idxMap[rawIdx];
          var fromPalette = data.getItemVisual(idx, 'colorFromPalette');

          if (fromPalette) {
            var itemStyle = data.ensureUniqueItemVisual(idx, 'style');
            itemStyle[colorKey] = seriesModel.getColorFromPalette(dataAll.getName(rawIdx) || rawIdx + '', colorScope, dataAll.count());
          }
        });
      });
    }
  };

  function aria(dom, ecModel) {
    var ariaModel = ecModel.getModel('aria');

    if (!ariaModel.get('show')) {
      return;
    } else if (ariaModel.get('description')) {
      dom.setAttribute('aria-label', ariaModel.get('description'));
      return;
    }

    var seriesCnt = 0;
    ecModel.eachSeries(function (seriesModel, idx) {
      ++seriesCnt;
    }, this);
    var maxDataCnt = ariaModel.get('data.maxCount') || 10;
    var maxSeriesCnt = ariaModel.get('series.maxCount') || 10;
    var displaySeriesCnt = Math.min(seriesCnt, maxSeriesCnt);
    var ariaLabel;

    if (seriesCnt < 1) {
      return;
    } else {
      var title = getTitle();

      if (title) {
        ariaLabel = replace(getConfig('general.withTitle'), {
          title: title
        });
      } else {
        ariaLabel = getConfig('general.withoutTitle');
      }

      var seriesLabels_1 = [];
      var prefix = seriesCnt > 1 ? 'series.multiple.prefix' : 'series.single.prefix';
      ariaLabel += replace(getConfig(prefix), {
        seriesCount: seriesCnt
      });
      ecModel.eachSeries(function (seriesModel, idx) {
        if (idx < displaySeriesCnt) {
          var seriesLabel = void 0;
          var seriesName = seriesModel.get('name');
          var seriesTpl = 'series.' + (seriesCnt > 1 ? 'multiple' : 'single') + '.';
          seriesLabel = getConfig(seriesName ? seriesTpl + 'withName' : seriesTpl + 'withoutName');
          seriesLabel = replace(seriesLabel, {
            seriesId: seriesModel.seriesIndex,
            seriesName: seriesModel.get('name'),
            seriesType: getSeriesTypeName(seriesModel.subType)
          });
          var data = seriesModel.getData();
          window.data = data;

          if (data.count() > maxDataCnt) {
            seriesLabel += replace(getConfig('data.partialData'), {
              displayCnt: maxDataCnt
            });
          } else {
            seriesLabel += getConfig('data.allData');
          }

          var dataLabels = [];

          for (var i = 0; i < data.count(); i++) {
            if (i < maxDataCnt) {
              var name_1 = data.getName(i);
              var value = retrieveRawValue(data, i);
              dataLabels.push(replace(name_1 ? getConfig('data.withName') : getConfig('data.withoutName'), {
                name: name_1,
                value: value
              }));
            }
          }

          seriesLabel += dataLabels.join(getConfig('data.separator.middle')) + getConfig('data.separator.end');
          seriesLabels_1.push(seriesLabel);
        }
      });
      ariaLabel += seriesLabels_1.join(getConfig('series.multiple.separator.middle')) + getConfig('series.multiple.separator.end');
      dom.setAttribute('aria-label', ariaLabel);
    }

    function replace(str, keyValues) {
      if (typeof str !== 'string') {
        return str;
      }

      var result = str;
      each(keyValues, function (value, key) {
        result = result.replace(new RegExp('\\{\\s*' + key + '\\s*\\}', 'g'), value);
      });
      return result;
    }

    function getConfig(path) {
      var userConfig = ariaModel.get(path);

      if (userConfig == null) {
        var pathArr = path.split('.');
        var result = ecModel.getLocale('aria');

        for (var i = 0; i < pathArr.length; ++i) {
          result = result[pathArr[i]];
        }

        return result;
      } else {
        return userConfig;
      }
    }

    function getTitle() {
      var title = ecModel.getModel('title').option;

      if (title && title.length) {
        title = title[0];
      }

      return title && title.text;
    }

    function getSeriesTypeName(type) {
      return ecModel.getLocale(['series', 'typeNames'])[type] || '自定义图';
    }
  }

  var PI$4 = Math.PI;

  function loadingDefault(api, opts) {
    opts = opts || {};
    defaults(opts, {
      text: 'loading',
      textColor: '#000',
      fontSize: '12px',
      maskColor: 'rgba(255, 255, 255, 0.8)',
      showSpinner: true,
      color: '#5470c6',
      spinnerRadius: 10,
      lineWidth: 5,
      zlevel: 0
    });
    var group = new Group();
    var mask = new Rect({
      style: {
        fill: opts.maskColor
      },
      zlevel: opts.zlevel,
      z: 10000
    });
    group.add(mask);
    var font = opts.fontSize + ' sans-serif';
    var labelRect = new Rect({
      style: {
        fill: 'none'
      },
      textContent: new ZRText({
        style: {
          text: opts.text,
          fill: opts.textColor,
          font: font
        }
      }),
      textConfig: {
        position: 'right',
        distance: 10
      },
      zlevel: opts.zlevel,
      z: 10001
    });
    group.add(labelRect);
    var arc;

    if (opts.showSpinner) {
      arc = new Arc({
        shape: {
          startAngle: -PI$4 / 2,
          endAngle: -PI$4 / 2 + 0.1,
          r: opts.spinnerRadius
        },
        style: {
          stroke: opts.color,
          lineCap: 'round',
          lineWidth: opts.lineWidth
        },
        zlevel: opts.zlevel,
        z: 10001
      });
      arc.animateShape(true).when(1000, {
        endAngle: PI$4 * 3 / 2
      }).start('circularInOut');
      arc.animateShape(true).when(1000, {
        startAngle: PI$4 * 3 / 2
      }).delay(300).start('circularInOut');
      group.add(arc);
    }

    group.resize = function () {
      var textWidth = getWidth(opts.text, font);
      var r = opts.showSpinner ? opts.spinnerRadius : 0;
      var cx = (api.getWidth() - r * 2 - (opts.showSpinner && textWidth ? 10 : 0) - textWidth) / 2 - (opts.showSpinner ? 0 : textWidth / 2);
      var cy = api.getHeight() / 2;
      opts.showSpinner && arc.setShape({
        cx: cx,
        cy: cy
      });
      labelRect.setShape({
        x: cx - r,
        y: cy - r,
        width: r * 2,
        height: r * 2
      });
      mask.setShape({
        x: 0,
        y: 0,
        width: api.getWidth(),
        height: api.getHeight()
      });
    };

    group.resize();
    return group;
  }

  var Scheduler = function () {
    function Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) {
      this._stageTaskMap = createHashMap();
      this.ecInstance = ecInstance;
      this.api = api;
      dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice();
      visualHandlers = this._visualHandlers = visualHandlers.slice();
      this._allHandlers = dataProcessorHandlers.concat(visualHandlers);
    }

    Scheduler.prototype.restoreData = function (ecModel, payload) {
      ecModel.restoreData(payload);

      this._stageTaskMap.each(function (taskRecord) {
        var overallTask = taskRecord.overallTask;
        overallTask && overallTask.dirty();
      });
    };

    Scheduler.prototype.getPerformArgs = function (task, isBlock) {
      if (!task.__pipeline) {
        return;
      }

      var pipeline = this._pipelineMap.get(task.__pipeline.id);

      var pCtx = pipeline.context;
      var incremental = !isBlock && pipeline.progressiveEnabled && (!pCtx || pCtx.progressiveRender) && task.__idxInPipeline > pipeline.blockIndex;
      var step = incremental ? pipeline.step : null;
      var modDataCount = pCtx && pCtx.modDataCount;
      var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null;
      return {
        step: step,
        modBy: modBy,
        modDataCount: modDataCount
      };
    };

    Scheduler.prototype.getPipeline = function (pipelineId) {
      return this._pipelineMap.get(pipelineId);
    };

    Scheduler.prototype.updateStreamModes = function (seriesModel, view) {
      var pipeline = this._pipelineMap.get(seriesModel.uid);

      var data = seriesModel.getData();
      var dataLen = data.count();
      var progressiveRender = pipeline.progressiveEnabled && view.incrementalPrepareRender && dataLen >= pipeline.threshold;
      var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold');
      var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;
      seriesModel.pipelineContext = pipeline.context = {
        progressiveRender: progressiveRender,
        modDataCount: modDataCount,
        large: large
      };
    };

    Scheduler.prototype.restorePipelines = function (ecModel) {
      var scheduler = this;
      var pipelineMap = scheduler._pipelineMap = createHashMap();
      ecModel.eachSeries(function (seriesModel) {
        var progressive = seriesModel.getProgressive();
        var pipelineId = seriesModel.uid;
        pipelineMap.set(pipelineId, {
          id: pipelineId,
          head: null,
          tail: null,
          threshold: seriesModel.getProgressiveThreshold(),
          progressiveEnabled: progressive && !(seriesModel.preventIncremental && seriesModel.preventIncremental()),
          blockIndex: -1,
          step: Math.round(progressive || 700),
          count: 0
        });

        scheduler._pipe(seriesModel, seriesModel.dataTask);
      });
    };

    Scheduler.prototype.prepareStageTasks = function () {
      var stageTaskMap = this._stageTaskMap;
      var ecModel = this.ecInstance.getModel();
      var api = this.api;
      each(this._allHandlers, function (handler) {
        var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, {});
        handler.reset && this._createSeriesStageTask(handler, record, ecModel, api);
        handler.overallReset && this._createOverallStageTask(handler, record, ecModel, api);
      }, this);
    };

    Scheduler.prototype.prepareView = function (view, model, ecModel, api) {
      var renderTask = view.renderTask;
      var context = renderTask.context;
      context.model = model;
      context.ecModel = ecModel;
      context.api = api;
      renderTask.__block = !view.incrementalPrepareRender;

      this._pipe(model, renderTask);
    };

    Scheduler.prototype.performDataProcessorTasks = function (ecModel, payload) {
      this._performStageTasks(this._dataProcessorHandlers, ecModel, payload, {
        block: true
      });
    };

    Scheduler.prototype.performVisualTasks = function (ecModel, payload, opt) {
      this._performStageTasks(this._visualHandlers, ecModel, payload, opt);
    };

    Scheduler.prototype._performStageTasks = function (stageHandlers, ecModel, payload, opt) {
      opt = opt || {};
      var unfinished = false;
      var scheduler = this;
      each(stageHandlers, function (stageHandler, idx) {
        if (opt.visualType && opt.visualType !== stageHandler.visualType) {
          return;
        }

        var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid);

        var seriesTaskMap = stageHandlerRecord.seriesTaskMap;
        var overallTask = stageHandlerRecord.overallTask;

        if (overallTask) {
          var overallNeedDirty_1;
          var agentStubMap = overallTask.agentStubMap;
          agentStubMap.each(function (stub) {
            if (needSetDirty(opt, stub)) {
              stub.dirty();
              overallNeedDirty_1 = true;
            }
          });
          overallNeedDirty_1 && overallTask.dirty();
          scheduler.updatePayload(overallTask, payload);
          var performArgs_1 = scheduler.getPerformArgs(overallTask, opt.block);
          agentStubMap.each(function (stub) {
            stub.perform(performArgs_1);
          });

          if (overallTask.perform(performArgs_1)) {
            unfinished = true;
          }
        } else if (seriesTaskMap) {
          seriesTaskMap.each(function (task, pipelineId) {
            if (needSetDirty(opt, task)) {
              task.dirty();
            }

            var performArgs = scheduler.getPerformArgs(task, opt.block);
            performArgs.skip = !stageHandler.performRawSeries && ecModel.isSeriesFiltered(task.context.model);
            scheduler.updatePayload(task, payload);

            if (task.perform(performArgs)) {
              unfinished = true;
            }
          });
        }
      });

      function needSetDirty(opt, task) {
        return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id));
      }

      this.unfinished = unfinished || this.unfinished;
    };

    Scheduler.prototype.performSeriesTasks = function (ecModel) {
      var unfinished;
      ecModel.eachSeries(function (seriesModel) {
        unfinished = seriesModel.dataTask.perform() || unfinished;
      });
      this.unfinished = unfinished || this.unfinished;
    };

    Scheduler.prototype.plan = function () {
      this._pipelineMap.each(function (pipeline) {
        var task = pipeline.tail;

        do {
          if (task.__block) {
            pipeline.blockIndex = task.__idxInPipeline;
            break;
          }

          task = task.getUpstream();
        } while (task);
      });
    };

    Scheduler.prototype.updatePayload = function (task, payload) {
      payload !== 'remain' && (task.context.payload = payload);
    };

    Scheduler.prototype._createSeriesStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) {
      var scheduler = this;
      var seriesTaskMap = stageHandlerRecord.seriesTaskMap || (stageHandlerRecord.seriesTaskMap = createHashMap());
      var seriesType = stageHandler.seriesType;
      var getTargetSeries = stageHandler.getTargetSeries;

      if (stageHandler.createOnAllSeries) {
        ecModel.eachRawSeries(create);
      } else if (seriesType) {
        ecModel.eachRawSeriesByType(seriesType, create);
      } else if (getTargetSeries) {
        getTargetSeries(ecModel, api).each(create);
      }

      function create(seriesModel) {
        var pipelineId = seriesModel.uid;
        var task = seriesTaskMap.get(pipelineId) || seriesTaskMap.set(pipelineId, createTask({
          plan: seriesTaskPlan,
          reset: seriesTaskReset,
          count: seriesTaskCount
        }));
        task.context = {
          model: seriesModel,
          ecModel: ecModel,
          api: api,
          useClearVisual: stageHandler.isVisual && !stageHandler.isLayout,
          plan: stageHandler.plan,
          reset: stageHandler.reset,
          scheduler: scheduler
        };

        scheduler._pipe(seriesModel, task);
      }

      var pipelineMap = scheduler._pipelineMap;
      seriesTaskMap.each(function (task, pipelineId) {
        if (!pipelineMap.get(pipelineId)) {
          task.dispose();
          seriesTaskMap.removeKey(pipelineId);
        }
      });
    };

    Scheduler.prototype._createOverallStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) {
      var scheduler = this;
      var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask || createTask({
        reset: overallTaskReset
      });
      overallTask.context = {
        ecModel: ecModel,
        api: api,
        overallReset: stageHandler.overallReset,
        scheduler: scheduler
      };
      var agentStubMap = overallTask.agentStubMap = overallTask.agentStubMap || createHashMap();
      var seriesType = stageHandler.seriesType;
      var getTargetSeries = stageHandler.getTargetSeries;
      var overallProgress = true;

      if (seriesType) {
        ecModel.eachRawSeriesByType(seriesType, createStub);
      } else if (getTargetSeries) {
        getTargetSeries(ecModel, api).each(createStub);
      } else {
        overallProgress = false;
        each(ecModel.getSeries(), createStub);
      }

      function createStub(seriesModel) {
        var pipelineId = seriesModel.uid;
        var stub = agentStubMap.get(pipelineId);

        if (!stub) {
          stub = agentStubMap.set(pipelineId, createTask({
            reset: stubReset,
            onDirty: stubOnDirty
          }));
          overallTask.dirty();
        }

        stub.context = {
          model: seriesModel,
          overallProgress: overallProgress
        };
        stub.agent = overallTask;
        stub.__block = overallProgress;

        scheduler._pipe(seriesModel, stub);
      }

      var pipelineMap = scheduler._pipelineMap;
      agentStubMap.each(function (stub, pipelineId) {
        if (!pipelineMap.get(pipelineId)) {
          stub.dispose();
          overallTask.dirty();
          agentStubMap.removeKey(pipelineId);
        }
      });
    };

    Scheduler.prototype._pipe = function (seriesModel, task) {
      var pipelineId = seriesModel.uid;

      var pipeline = this._pipelineMap.get(pipelineId);

      !pipeline.head && (pipeline.head = task);
      pipeline.tail && pipeline.tail.pipe(task);
      pipeline.tail = task;
      task.__idxInPipeline = pipeline.count++;
      task.__pipeline = pipeline;
    };

    Scheduler.wrapStageHandler = function (stageHandler, visualType) {
      if (isFunction(stageHandler)) {
        stageHandler = {
          overallReset: stageHandler,
          seriesType: detectSeriseType(stageHandler)
        };
      }

      stageHandler.uid = getUID('stageHandler');
      visualType && (stageHandler.visualType = visualType);
      return stageHandler;
    };

    return Scheduler;
  }();

  function overallTaskReset(context) {
    context.overallReset(context.ecModel, context.api, context.payload);
  }

  function stubReset(context) {
    return context.overallProgress && stubProgress;
  }

  function stubProgress() {
    this.agent.dirty();
    this.getDownstream().dirty();
  }

  function stubOnDirty() {
    this.agent && this.agent.dirty();
  }

  function seriesTaskPlan(context) {
    return context.plan ? context.plan(context.model, context.ecModel, context.api, context.payload) : null;
  }

  function seriesTaskReset(context) {
    if (context.useClearVisual) {
      context.data.clearAllVisual();
    }

    var resetDefines = context.resetDefines = normalizeToArray(context.reset(context.model, context.ecModel, context.api, context.payload));
    return resetDefines.length > 1 ? map(resetDefines, function (v, idx) {
      return makeSeriesTaskProgress(idx);
    }) : singleSeriesTaskProgress;
  }

  var singleSeriesTaskProgress = makeSeriesTaskProgress(0);

  function makeSeriesTaskProgress(resetDefineIdx) {
    return function (params, context) {
      var data = context.data;
      var resetDefine = context.resetDefines[resetDefineIdx];

      if (resetDefine && resetDefine.dataEach) {
        for (var i = params.start; i < params.end; i++) {
          resetDefine.dataEach(data, i);
        }
      } else if (resetDefine && resetDefine.progress) {
        resetDefine.progress(params, data);
      }
    };
  }

  function seriesTaskCount(context) {
    return context.data.count();
  }

  function detectSeriseType(legacyFunc) {
    seriesType = null;

    try {
      legacyFunc(ecModelMock, apiMock);
    } catch (e) {}

    return seriesType;
  }

  var ecModelMock = {};
  var apiMock = {};
  var seriesType;
  mockMethods(ecModelMock, GlobalModel);
  mockMethods(apiMock, ExtensionAPI);

  ecModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) {
    seriesType = type;
  };

  ecModelMock.eachComponent = function (cond) {
    if (cond.mainType === 'series' && cond.subType) {
      seriesType = cond.subType;
    }
  };

  function mockMethods(target, Clz) {
    for (var name_1 in Clz.prototype) {
      target[name_1] = noop;
    }
  }

  var colorAll = ['#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'];
  var lightTheme = {
    color: colorAll,
    colorLayer: [['#37A2DA', '#ffd85c', '#fd7b5f'], ['#37A2DA', '#67E0E3', '#FFDB5C', '#ff9f7f', '#E062AE', '#9d96f5'], ['#37A2DA', '#32C5E9', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#e7bcf3', '#8378EA', '#96BFFF'], colorAll]
  };
  var contrastColor = '#B9B8CE';
  var backgroundColor = '#100C2A';

  var axisCommon = function () {
    return {
      axisLine: {
        lineStyle: {
          color: contrastColor
        }
      },
      splitLine: {
        lineStyle: {
          color: '#484753'
        }
      },
      splitArea: {
        areaStyle: {
          color: ['rgba(255,255,255,0.02)', 'rgba(255,255,255,0.05)']
        }
      },
      minorSplitLine: {
        lineStyle: {
          color: '#20203B'
        }
      }
    };
  };

  var colorPalette = ['#4992ff', '#7cffb2', '#fddd60', '#ff6e76', '#58d9f9', '#05c091', '#ff8a45', '#8d48e3', '#dd79ff'];
  var theme = {
    darkMode: true,
    color: colorPalette,
    backgroundColor: backgroundColor,
    axisPointer: {
      lineStyle: {
        color: '#817f91'
      },
      crossStyle: {
        color: '#817f91'
      },
      label: {
        color: '#fff'
      }
    },
    legend: {
      textStyle: {
        color: contrastColor
      }
    },
    textStyle: {
      color: contrastColor
    },
    title: {
      textStyle: {
        color: '#EEF1FA'
      },
      subtextStyle: {
        color: '#B9B8CE'
      }
    },
    toolbox: {
      iconStyle: {
        normal: {
          borderColor: contrastColor
        }
      }
    },
    dataZoom: {
      borderColor: '#71708A',
      textStyle: {
        color: contrastColor
      },
      brushStyle: {
        color: 'rgba(135,163,206,0.3)'
      },
      handleStyle: {
        color: '#353450',
        borderColor: '#C5CBE3'
      },
      moveHandleStyle: {
        color: '#B0B6C3',
        opacity: 0.3
      },
      fillerColor: 'rgba(135,163,206,0.2)',
      emphasis: {
        handleStyle: {
          borderColor: '#91B7F2',
          color: '#4D587D'
        },
        moveHandleStyle: {
          color: '#636D9A',
          opacity: 0.7
        }
      },
      dataBackground: {
        lineStyle: {
          color: '#71708A',
          width: 1
        },
        areaStyle: {
          color: '#71708A'
        }
      },
      selectedDataBackground: {
        lineStyle: {
          color: '#87A3CE'
        },
        areaStyle: {
          color: '#87A3CE'
        }
      }
    },
    visualMap: {
      textStyle: {
        color: contrastColor
      }
    },
    timeline: {
      lineStyle: {
        color: contrastColor
      },
      label: {
        textStyle: {
          color: contrastColor
        }
      },
      controlStyle: {
        color: contrastColor,
        borderColor: contrastColor
      }
    },
    calendar: {
      itemStyle: {
        color: backgroundColor
      },
      dayLabel: {
        color: contrastColor
      },
      monthLabel: {
        color: contrastColor
      },
      yearLabel: {
        color: contrastColor
      }
    },
    timeAxis: axisCommon(),
    logAxis: axisCommon(),
    valueAxis: axisCommon(),
    categoryAxis: axisCommon(),
    line: {
      symbol: 'circle'
    },
    graph: {
      color: colorPalette
    },
    gauge: {
      title: {
        textStyle: {
          color: contrastColor
        }
      }
    },
    candlestick: {
      itemStyle: {
        normal: {
          color: '#FD1050',
          color0: '#0CF49B',
          borderColor: '#FD1050',
          borderColor0: '#0CF49B'
        }
      }
    }
  };
  theme.categoryAxis.splitLine.show = false;

  var DatasetModel = function (_super) {
    __extends(DatasetModel, _super);

    function DatasetModel() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = 'dataset';
      return _this;
    }

    DatasetModel.prototype.init = function (option, parentModel, ecModel) {
      _super.prototype.init.call(this, option, parentModel, ecModel);

      this._sourceManager = new SourceManager(this);
      disableTransformOptionMerge(this);
    };

    DatasetModel.prototype.mergeOption = function (newOption, ecModel) {
      _super.prototype.mergeOption.call(this, newOption, ecModel);

      disableTransformOptionMerge(this);
    };

    DatasetModel.prototype.optionUpdated = function () {
      this._sourceManager.dirty();
    };

    DatasetModel.prototype.getSourceManager = function () {
      return this._sourceManager;
    };

    DatasetModel.type = 'dataset';
    DatasetModel.defaultOption = {
      seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN
    };
    return DatasetModel;
  }(ComponentModel);

  ComponentModel.registerClass(DatasetModel);

  var DatasetView = function (_super) {
    __extends(DatasetView, _super);

    function DatasetView() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = 'dataset';
      return _this;
    }

    DatasetView.type = 'dataset';
    return DatasetView;
  }(ComponentView);

  ComponentView.registerClass(DatasetView);
  var storage = createHashMap();
  var mapDataStorage = {
    registerMap: function (mapName, rawDef, rawSpecialAreas) {
      var records;

      if (isArray(rawDef)) {
        records = rawDef;
      } else if (rawDef.svg) {
        records = [{
          type: 'svg',
          source: rawDef.svg,
          specialAreas: rawDef.specialAreas
        }];
      } else {
        var geoSource = rawDef.geoJson || rawDef.geoJSON;

        if (geoSource && !rawDef.features) {
          rawSpecialAreas = rawDef.specialAreas;
          rawDef = geoSource;
        }

        records = [{
          type: 'geoJSON',
          source: rawDef,
          specialAreas: rawSpecialAreas
        }];
      }

      each(records, function (record) {
        var type = record.type;
        type === 'geoJson' && (type = record.type = 'geoJSON');
        var parse = parsers[type];

        if (true) {
          assert(parse, 'Illegal map type: ' + type);
        }

        parse(record);
      });
      return storage.set(mapName, records);
    },
    retrieveMap: function (mapName) {
      return storage.get(mapName);
    }
  };
  var parsers = {
    geoJSON: function (record) {
      var source = record.source;
      record.geoJSON = !isString(source) ? source : typeof JSON !== 'undefined' && JSON.parse ? JSON.parse(source) : new Function('return (' + source + ');')();
    },
    svg: function (record) {
      record.svgXML = parseXML(record.source);
    }
  };

  var ECEventProcessor = function () {
    function ECEventProcessor() {}

    ECEventProcessor.prototype.normalizeQuery = function (query) {
      var cptQuery = {};
      var dataQuery = {};
      var otherQuery = {};

      if (isString(query)) {
        var condCptType = parseClassType(query);
        cptQuery.mainType = condCptType.main || null;
        cptQuery.subType = condCptType.sub || null;
      } else {
        var suffixes_1 = ['Index', 'Name', 'Id'];
        var dataKeys_1 = {
          name: 1,
          dataIndex: 1,
          dataType: 1
        };
        each(query, function (val, key) {
          var reserved = false;

          for (var i = 0; i < suffixes_1.length; i++) {
            var propSuffix = suffixes_1[i];
            var suffixPos = key.lastIndexOf(propSuffix);

            if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {
              var mainType = key.slice(0, suffixPos);

              if (mainType !== 'data') {
                cptQuery.mainType = mainType;
                cptQuery[propSuffix.toLowerCase()] = val;
                reserved = true;
              }
            }
          }

          if (dataKeys_1.hasOwnProperty(key)) {
            dataQuery[key] = val;
            reserved = true;
          }

          if (!reserved) {
            otherQuery[key] = val;
          }
        });
      }

      return {
        cptQuery: cptQuery,
        dataQuery: dataQuery,
        otherQuery: otherQuery
      };
    };

    ECEventProcessor.prototype.filter = function (eventType, query) {
      var eventInfo = this.eventInfo;

      if (!eventInfo) {
        return true;
      }

      var targetEl = eventInfo.targetEl;
      var packedEvent = eventInfo.packedEvent;
      var model = eventInfo.model;
      var view = eventInfo.view;

      if (!model || !view) {
        return true;
      }

      var cptQuery = query.cptQuery;
      var dataQuery = query.dataQuery;
      return check(cptQuery, model, 'mainType') && check(cptQuery, model, 'subType') && check(cptQuery, model, 'index', 'componentIndex') && check(cptQuery, model, 'name') && check(cptQuery, model, 'id') && check(dataQuery, packedEvent, 'name') && check(dataQuery, packedEvent, 'dataIndex') && check(dataQuery, packedEvent, 'dataType') && (!view.filterForExposedEvent || view.filterForExposedEvent(eventType, query.otherQuery, targetEl, packedEvent));

      function check(query, host, prop, propOnHost) {
        return query[prop] == null || host[propOnHost || prop] === query[prop];
      }
    };

    ECEventProcessor.prototype.afterTrigger = function () {
      this.eventInfo = null;
    };

    return ECEventProcessor;
  }();

  var seriesSymbolTask = {
    createOnAllSeries: true,
    performRawSeries: true,
    reset: function (seriesModel, ecModel) {
      var data = seriesModel.getData();

      if (seriesModel.legendSymbol) {
        data.setVisual('legendSymbol', seriesModel.legendSymbol);
      }

      if (!seriesModel.hasSymbolVisual) {
        return;
      }

      var symbolType = seriesModel.get('symbol');
      var symbolSize = seriesModel.get('symbolSize');
      var keepAspect = seriesModel.get('symbolKeepAspect');
      var symbolRotate = seriesModel.get('symbolRotate');
      var hasSymbolTypeCallback = isFunction(symbolType);
      var hasSymbolSizeCallback = isFunction(symbolSize);
      var hasSymbolRotateCallback = isFunction(symbolRotate);
      var hasCallback = hasSymbolTypeCallback || hasSymbolSizeCallback || hasSymbolRotateCallback;
      var seriesSymbol = !hasSymbolTypeCallback && symbolType ? symbolType : seriesModel.defaultSymbol;
      var seriesSymbolSize = !hasSymbolSizeCallback ? symbolSize : null;
      var seriesSymbolRotate = !hasSymbolRotateCallback ? symbolRotate : null;
      data.setVisual({
        legendSymbol: seriesModel.legendSymbol || seriesSymbol,
        symbol: seriesSymbol,
        symbolSize: seriesSymbolSize,
        symbolKeepAspect: keepAspect,
        symbolRotate: seriesSymbolRotate
      });

      if (ecModel.isSeriesFiltered(seriesModel)) {
        return;
      }

      function dataEach(data, idx) {
        var rawValue = seriesModel.getRawValue(idx);
        var params = seriesModel.getDataParams(idx);
        hasSymbolTypeCallback && data.setItemVisual(idx, 'symbol', symbolType(rawValue, params));
        hasSymbolSizeCallback && data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));
        hasSymbolRotateCallback && data.setItemVisual(idx, 'symbolRotate', symbolRotate(rawValue, params));
      }

      return {
        dataEach: hasCallback ? dataEach : null
      };
    }
  };
  var dataSymbolTask = {
    createOnAllSeries: true,
    performRawSeries: true,
    reset: function (seriesModel, ecModel) {
      if (!seriesModel.hasSymbolVisual) {
        return;
      }

      if (ecModel.isSeriesFiltered(seriesModel)) {
        return;
      }

      var data = seriesModel.getData();

      function dataEach(data, idx) {
        var itemModel = data.getItemModel(idx);
        var itemSymbolType = itemModel.getShallow('symbol', true);
        var itemSymbolSize = itemModel.getShallow('symbolSize', true);
        var itemSymbolRotate = itemModel.getShallow('symbolRotate', true);
        var itemSymbolKeepAspect = itemModel.getShallow('symbolKeepAspect', true);

        if (itemSymbolType != null) {
          data.setItemVisual(idx, 'symbol', itemSymbolType);
        }

        if (itemSymbolSize != null) {
          data.setItemVisual(idx, 'symbolSize', itemSymbolSize);
        }

        if (itemSymbolRotate != null) {
          data.setItemVisual(idx, 'symbolRotate', itemSymbolRotate);
        }

        if (itemSymbolKeepAspect != null) {
          data.setItemVisual(idx, 'symbolKeepAspect', itemSymbolKeepAspect);
        }
      }

      return {
        dataEach: data.hasItemOption ? dataEach : null
      };
    }
  };

  function getItemVisualFromData(data, dataIndex, key) {
    switch (key) {
      case 'color':
        var style = data.getItemVisual(dataIndex, 'style');
        return style[data.getVisual('drawType')];

      case 'opacity':
        return data.getItemVisual(dataIndex, 'style').opacity;

      case 'symbol':
      case 'symbolSize':
      case 'liftZ':
        return data.getItemVisual(dataIndex, key);

      default:
        if (true) {
          console.warn("Unknown visual type " + key);
        }

    }
  }

  function getVisualFromData(data, key) {
    switch (key) {
      case 'color':
        var style = data.getVisual('style');
        return style[data.getVisual('drawType')];

      case 'opacity':
        return data.getVisual('style').opacity;

      case 'symbol':
      case 'symbolSize':
      case 'liftZ':
        return data.getVisual(key);

      default:
        if (true) {
          console.warn("Unknown visual type " + key);
        }

    }
  }

  var PI2$5 = Math.PI * 2;
  var CMD$3 = PathProxy.CMD;
  var DEFAULT_SEARCH_SPACE = ['top', 'right', 'bottom', 'left'];

  function getCandidateAnchor(pos, distance, rect, outPt, outDir) {
    var width = rect.width;
    var height = rect.height;

    switch (pos) {
      case 'top':
        outPt.set(rect.x + width / 2, rect.y - distance);
        outDir.set(0, -1);
        break;

      case 'bottom':
        outPt.set(rect.x + width / 2, rect.y + height + distance);
        outDir.set(0, 1);
        break;

      case 'left':
        outPt.set(rect.x - distance, rect.y + height / 2);
        outDir.set(-1, 0);
        break;

      case 'right':
        outPt.set(rect.x + width + distance, rect.y + height / 2);
        outDir.set(1, 0);
        break;
    }
  }

  function projectPointToArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y, out) {
    x -= cx;
    y -= cy;
    var d = Math.sqrt(x * x + y * y);
    x /= d;
    y /= d;
    var ox = x * r + cx;
    var oy = y * r + cy;

    if (Math.abs(startAngle - endAngle) % PI2$5 < 1e-4) {
      out[0] = ox;
      out[1] = oy;
      return d - r;
    }

    if (anticlockwise) {
      var tmp = startAngle;
      startAngle = normalizeRadian(endAngle);
      endAngle = normalizeRadian(tmp);
    } else {
      startAngle = normalizeRadian(startAngle);
      endAngle = normalizeRadian(endAngle);
    }

    if (startAngle > endAngle) {
      endAngle += PI2$5;
    }

    var angle = Math.atan2(y, x);

    if (angle < 0) {
      angle += PI2$5;
    }

    if (angle >= startAngle && angle <= endAngle || angle + PI2$5 >= startAngle && angle + PI2$5 <= endAngle) {
      out[0] = ox;
      out[1] = oy;
      return d - r;
    }

    var x1 = r * Math.cos(startAngle) + cx;
    var y1 = r * Math.sin(startAngle) + cy;
    var x2 = r * Math.cos(endAngle) + cx;
    var y2 = r * Math.sin(endAngle) + cy;
    var d1 = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y);
    var d2 = (x2 - x) * (x2 - x) + (y2 - y) * (y2 - y);

    if (d1 < d2) {
      out[0] = x1;
      out[1] = y1;
      return Math.sqrt(d1);
    } else {
      out[0] = x2;
      out[1] = y2;
      return Math.sqrt(d2);
    }
  }

  function projectPointToLine(x1, y1, x2, y2, x, y, out, limitToEnds) {
    var dx = x - x1;
    var dy = y - y1;
    var dx1 = x2 - x1;
    var dy1 = y2 - y1;
    var lineLen = Math.sqrt(dx1 * dx1 + dy1 * dy1);
    dx1 /= lineLen;
    dy1 /= lineLen;
    var projectedLen = dx * dx1 + dy * dy1;
    var t = projectedLen / lineLen;

    if (limitToEnds) {
      t = Math.min(Math.max(t, 0), 1);
    }

    t *= lineLen;
    var ox = out[0] = x1 + t * dx1;
    var oy = out[1] = y1 + t * dy1;
    return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y));
  }

  function projectPointToRect(x1, y1, width, height, x, y, out) {
    if (width < 0) {
      x1 = x1 + width;
      width = -width;
    }

    if (height < 0) {
      y1 = y1 + height;
      height = -height;
    }

    var x2 = x1 + width;
    var y2 = y1 + height;
    var ox = out[0] = Math.min(Math.max(x, x1), x2);
    var oy = out[1] = Math.min(Math.max(y, y1), y2);
    return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y));
  }

  var tmpPt = [];

  function nearestPointOnRect(pt, rect, out) {
    var dist = projectPointToRect(rect.x, rect.y, rect.width, rect.height, pt.x, pt.y, tmpPt);
    out.set(tmpPt[0], tmpPt[1]);
    return dist;
  }

  function nearestPointOnPath(pt, path, out) {
    var xi = 0;
    var yi = 0;
    var x0 = 0;
    var y0 = 0;
    var x1;
    var y1;
    var minDist = Infinity;
    var data = path.data;
    var x = pt.x;
    var y = pt.y;

    for (var i = 0; i < data.length;) {
      var cmd = data[i++];

      if (i === 1) {
        xi = data[i];
        yi = data[i + 1];
        x0 = xi;
        y0 = yi;
      }

      var d = minDist;

      switch (cmd) {
        case CMD$3.M:
          x0 = data[i++];
          y0 = data[i++];
          xi = x0;
          yi = y0;
          break;

        case CMD$3.L:
          d = projectPointToLine(xi, yi, data[i], data[i + 1], x, y, tmpPt, true);
          xi = data[i++];
          yi = data[i++];
          break;

        case CMD$3.C:
          d = cubicProjectPoint(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt);
          xi = data[i++];
          yi = data[i++];
          break;

        case CMD$3.Q:
          d = quadraticProjectPoint(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt);
          xi = data[i++];
          yi = data[i++];
          break;

        case CMD$3.A:
          var cx = data[i++];
          var cy = data[i++];
          var rx = data[i++];
          var ry = data[i++];
          var theta = data[i++];
          var dTheta = data[i++];
          i += 1;
          var anticlockwise = !!(1 - data[i++]);
          x1 = Math.cos(theta) * rx + cx;
          y1 = Math.sin(theta) * ry + cy;

          if (i <= 1) {
            x0 = x1;
            y0 = y1;
          }

          var _x = (x - cx) * ry / rx + cx;

          d = projectPointToArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y, tmpPt);
          xi = Math.cos(theta + dTheta) * rx + cx;
          yi = Math.sin(theta + dTheta) * ry + cy;
          break;

        case CMD$3.R:
          x0 = xi = data[i++];
          y0 = yi = data[i++];
          var width = data[i++];
          var height = data[i++];
          d = projectPointToRect(x0, y0, width, height, x, y, tmpPt);
          break;

        case CMD$3.Z:
          d = projectPointToLine(xi, yi, x0, y0, x, y, tmpPt, true);
          xi = x0;
          yi = y0;
          break;
      }

      if (d < minDist) {
        minDist = d;
        out.set(tmpPt[0], tmpPt[1]);
      }
    }

    return minDist;
  }

  var pt0 = new Point();
  var pt1 = new Point();
  var pt2 = new Point();
  var dir = new Point();
  var dir2 = new Point();

  function updateLabelLinePoints(target, labelLineModel) {
    if (!target) {
      return;
    }

    var labelLine = target.getTextGuideLine();
    var label = target.getTextContent();

    if (!(label && labelLine)) {
      return;
    }

    var labelGuideConfig = target.textGuideLineConfig || {};
    var points = [[0, 0], [0, 0], [0, 0]];
    var searchSpace = labelGuideConfig.candidates || DEFAULT_SEARCH_SPACE;
    var labelRect = label.getBoundingRect().clone();
    labelRect.applyTransform(label.getComputedTransform());
    var minDist = Infinity;
    var anchorPoint = labelGuideConfig && labelGuideConfig.anchor;
    var targetTransform = target.getComputedTransform();
    var targetInversedTransform = targetTransform && invert([], targetTransform);
    var len = labelLineModel.get('length2') || 0;

    if (anchorPoint) {
      pt2.copy(anchorPoint);
    }

    for (var i = 0; i < searchSpace.length; i++) {
      var candidate = searchSpace[i];
      getCandidateAnchor(candidate, 0, labelRect, pt0, dir);
      Point.scaleAndAdd(pt1, pt0, dir, len);
      pt1.transform(targetInversedTransform);
      var boundingRect = target.getBoundingRect();
      var dist = anchorPoint ? anchorPoint.distance(pt1) : target instanceof Path ? nearestPointOnPath(pt1, target.path, pt2) : nearestPointOnRect(pt1, boundingRect, pt2);

      if (dist < minDist) {
        minDist = dist;
        pt1.transform(targetTransform);
        pt2.transform(targetTransform);
        pt2.toArray(points[0]);
        pt1.toArray(points[1]);
        pt0.toArray(points[2]);
      }
    }

    limitTurnAngle(points, labelLineModel.get('minTurnAngle'));
    labelLine.setShape({
      points: points
    });
  }

  var tmpArr = [];
  var tmpProjPoint = new Point();

  function limitTurnAngle(linePoints, minTurnAngle) {
    if (!(minTurnAngle <= 180 && minTurnAngle > 0)) {
      return;
    }

    minTurnAngle = minTurnAngle / 180 * Math.PI;
    pt0.fromArray(linePoints[0]);
    pt1.fromArray(linePoints[1]);
    pt2.fromArray(linePoints[2]);
    Point.sub(dir, pt0, pt1);
    Point.sub(dir2, pt2, pt1);
    var len1 = dir.len();
    var len2 = dir2.len();

    if (len1 < 1e-3 || len2 < 1e-3) {
      return;
    }

    dir.scale(1 / len1);
    dir2.scale(1 / len2);
    var angleCos = dir.dot(dir2);
    var minTurnAngleCos = Math.cos(minTurnAngle);

    if (minTurnAngleCos < angleCos) {
      var d = projectPointToLine(pt1.x, pt1.y, pt2.x, pt2.y, pt0.x, pt0.y, tmpArr, false);
      tmpProjPoint.fromArray(tmpArr);
      tmpProjPoint.scaleAndAdd(dir2, d / Math.tan(Math.PI - minTurnAngle));
      var t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y);

      if (isNaN(t)) {
        return;
      }

      if (t < 0) {
        Point.copy(tmpProjPoint, pt1);
      } else if (t > 1) {
        Point.copy(tmpProjPoint, pt2);
      }

      tmpProjPoint.toArray(linePoints[1]);
    }
  }

  function limitSurfaceAngle(linePoints, surfaceNormal, maxSurfaceAngle) {
    if (!(maxSurfaceAngle <= 180 && maxSurfaceAngle > 0)) {
      return;
    }

    maxSurfaceAngle = maxSurfaceAngle / 180 * Math.PI;
    pt0.fromArray(linePoints[0]);
    pt1.fromArray(linePoints[1]);
    pt2.fromArray(linePoints[2]);
    Point.sub(dir, pt1, pt0);
    Point.sub(dir2, pt2, pt1);
    var len1 = dir.len();
    var len2 = dir2.len();

    if (len1 < 1e-3 || len2 < 1e-3) {
      return;
    }

    dir.scale(1 / len1);
    dir2.scale(1 / len2);
    var angleCos = dir.dot(surfaceNormal);
    var maxSurfaceAngleCos = Math.cos(maxSurfaceAngle);

    if (angleCos < maxSurfaceAngleCos) {
      var d = projectPointToLine(pt1.x, pt1.y, pt2.x, pt2.y, pt0.x, pt0.y, tmpArr, false);
      tmpProjPoint.fromArray(tmpArr);
      var HALF_PI = Math.PI / 2;
      var angle2 = Math.acos(dir2.dot(surfaceNormal));
      var newAngle = HALF_PI + angle2 - maxSurfaceAngle;

      if (newAngle >= HALF_PI) {
        Point.copy(tmpProjPoint, pt2);
      } else {
        tmpProjPoint.scaleAndAdd(dir2, d / Math.tan(Math.PI / 2 - newAngle));
        var t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y);

        if (isNaN(t)) {
          return;
        }

        if (t < 0) {
          Point.copy(tmpProjPoint, pt1);
        } else if (t > 1) {
          Point.copy(tmpProjPoint, pt2);
        }
      }

      tmpProjPoint.toArray(linePoints[1]);
    }
  }

  function setLabelLineState(labelLine, ignore, stateName, stateModel) {
    var isNormal = stateName === 'normal';
    var stateObj = isNormal ? labelLine : labelLine.ensureState(stateName);
    stateObj.ignore = ignore;
    var smooth = stateModel.get('smooth');

    if (smooth && smooth === true) {
      smooth = 0.3;
    }

    stateObj.shape = stateObj.shape || {};

    if (smooth > 0) {
      stateObj.shape.smooth = smooth;
    }

    var styleObj = stateModel.getModel('lineStyle').getLineStyle();
    isNormal ? labelLine.useStyle(styleObj) : stateObj.style = styleObj;
  }

  function buildLabelLinePath(path, shape) {
    var smooth = shape.smooth;
    var points = shape.points;

    if (!points) {
      return;
    }

    path.moveTo(points[0][0], points[0][1]);

    if (smooth > 0 && points.length >= 3) {
      var len1 = dist(points[0], points[1]);
      var len2 = dist(points[1], points[2]);

      if (!len1 || !len2) {
        path.lineTo(points[1][0], points[1][1]);
        path.lineTo(points[2][0], points[2][1]);
        return;
      }

      var moveLen = Math.min(len1, len2) * smooth;
      var midPoint0 = lerp([], points[1], points[0], moveLen / len1);
      var midPoint2 = lerp([], points[1], points[2], moveLen / len2);
      var midPoint1 = lerp([], midPoint0, midPoint2, 0.5);
      path.bezierCurveTo(midPoint0[0], midPoint0[1], midPoint0[0], midPoint0[1], midPoint1[0], midPoint1[1]);
      path.bezierCurveTo(midPoint2[0], midPoint2[1], midPoint2[0], midPoint2[1], points[2][0], points[2][1]);
    } else {
      for (var i = 1; i < points.length; i++) {
        path.lineTo(points[i][0], points[i][1]);
      }
    }
  }

  function setLabelLineStyle(targetEl, statesModels, defaultStyle) {
    var labelLine = targetEl.getTextGuideLine();
    var label = targetEl.getTextContent();

    if (!label) {
      if (labelLine) {
        targetEl.removeTextGuideLine();
      }

      return;
    }

    var normalModel = statesModels.normal;
    var showNormal = normalModel.get('show');
    var labelIgnoreNormal = label.ignore;

    for (var i = 0; i < DISPLAY_STATES.length; i++) {
      var stateName = DISPLAY_STATES[i];
      var stateModel = statesModels[stateName];
      var isNormal = stateName === 'normal';

      if (stateModel) {
        var stateShow = stateModel.get('show');
        var isLabelIgnored = isNormal ? labelIgnoreNormal : retrieve2(label.states[stateName] && label.states[stateName].ignore, labelIgnoreNormal);

        if (isLabelIgnored || !retrieve2(stateShow, showNormal)) {
          var stateObj = isNormal ? labelLine : labelLine && labelLine.states.normal;

          if (stateObj) {
            stateObj.ignore = true;
          }

          continue;
        }

        if (!labelLine) {
          labelLine = new Polyline();
          targetEl.setTextGuideLine(labelLine);

          if (!isNormal && (labelIgnoreNormal || !showNormal)) {
            setLabelLineState(labelLine, true, 'normal', statesModels.normal);
          }

          if (targetEl.stateProxy) {
            labelLine.stateProxy = targetEl.stateProxy;
          }
        }

        setLabelLineState(labelLine, false, stateName, stateModel);
      }
    }

    if (labelLine) {
      defaults(labelLine.style, defaultStyle);
      labelLine.style.fill = null;
      labelLine.buildPath = buildLabelLinePath;
    }
  }

  function getLabelLineStatesModels(itemModel, labelLineName) {
    labelLineName = labelLineName || 'labelLine';
    var statesModels = {
      normal: itemModel.getModel(labelLineName)
    };

    for (var i = 0; i < SPECIAL_STATES.length; i++) {
      var stateName = SPECIAL_STATES[i];
      statesModels[stateName] = itemModel.getModel([stateName, labelLineName]);
    }

    return statesModels;
  }

  function prepareLayoutList(input) {
    var list = [];

    for (var i = 0; i < input.length; i++) {
      var rawItem = input[i];

      if (rawItem.defaultAttr.ignore) {
        continue;
      }

      var label = rawItem.label;
      var transform = label.getComputedTransform();
      var localRect = label.getBoundingRect();
      var isAxisAligned = !transform || transform[1] < 1e-5 && transform[2] < 1e-5;
      var minMargin = label.style.margin || 0;
      var globalRect = localRect.clone();
      globalRect.applyTransform(transform);
      globalRect.x -= minMargin / 2;
      globalRect.y -= minMargin / 2;
      globalRect.width += minMargin;
      globalRect.height += minMargin;
      var obb = isAxisAligned ? new OrientedBoundingRect(localRect, transform) : null;
      list.push({
        label: label,
        labelLine: rawItem.labelLine,
        rect: globalRect,
        localRect: localRect,
        obb: obb,
        priority: rawItem.priority,
        defaultAttr: rawItem.defaultAttr,
        layoutOption: rawItem.computedLayoutOption,
        axisAligned: isAxisAligned,
        transform: transform
      });
    }

    return list;
  }

  function shiftLayout(list, xyDim, sizeDim, minBound, maxBound, balanceShift) {
    var len = list.length;

    if (len < 2) {
      return;
    }

    list.sort(function (a, b) {
      return a.rect[xyDim] - b.rect[xyDim];
    });
    var lastPos = 0;
    var delta;
    var adjusted = false;
    var totalShifts = 0;

    for (var i = 0; i < len; i++) {
      var item = list[i];
      var rect = item.rect;
      delta = rect[xyDim] - lastPos;

      if (delta < 0) {
        rect[xyDim] -= delta;
        item.label[xyDim] -= delta;
        adjusted = true;
      }

      var shift = Math.max(-delta, 0);
      totalShifts += shift;
      lastPos = rect[xyDim] + rect[sizeDim];
    }

    if (totalShifts > 0 && balanceShift) {
      shiftList(-totalShifts / len, 0, len);
    }

    var first = list[0];
    var last = list[len - 1];
    var minGap;
    var maxGap;
    updateMinMaxGap();
    minGap < 0 && squeezeGaps(-minGap, 0.8);
    maxGap < 0 && squeezeGaps(maxGap, 0.8);
    updateMinMaxGap();
    takeBoundsGap(minGap, maxGap, 1);
    takeBoundsGap(maxGap, minGap, -1);
    updateMinMaxGap();

    if (minGap < 0) {
      squeezeWhenBailout(-minGap);
    }

    if (maxGap < 0) {
      squeezeWhenBailout(maxGap);
    }

    function updateMinMaxGap() {
      minGap = first.rect[xyDim] - minBound;
      maxGap = maxBound - last.rect[xyDim] - last.rect[sizeDim];
    }

    function takeBoundsGap(gapThisBound, gapOtherBound, moveDir) {
      if (gapThisBound < 0) {
        var moveFromMaxGap = Math.min(gapOtherBound, -gapThisBound);

        if (moveFromMaxGap > 0) {
          shiftList(moveFromMaxGap * moveDir, 0, len);
          var remained = moveFromMaxGap + gapThisBound;

          if (remained < 0) {
            squeezeGaps(-remained * moveDir, 1);
          }
        } else {
          squeezeGaps(-gapThisBound * moveDir, 1);
        }
      }
    }

    function shiftList(delta, start, end) {
      if (delta !== 0) {
        adjusted = true;
      }

      for (var i = start; i < end; i++) {
        var item = list[i];
        var rect = item.rect;
        rect[xyDim] += delta;
        item.label[xyDim] += delta;
      }
    }

    function squeezeGaps(delta, maxSqeezePercent) {
      var gaps = [];
      var totalGaps = 0;

      for (var i = 1; i < len; i++) {
        var prevItemRect = list[i - 1].rect;
        var gap = Math.max(list[i].rect[xyDim] - prevItemRect[xyDim] - prevItemRect[sizeDim], 0);
        gaps.push(gap);
        totalGaps += gap;
      }

      if (!totalGaps) {
        return;
      }

      var squeezePercent = Math.min(Math.abs(delta) / totalGaps, maxSqeezePercent);

      if (delta > 0) {
        for (var i = 0; i < len - 1; i++) {
          var movement = gaps[i] * squeezePercent;
          shiftList(movement, 0, i + 1);
        }
      } else {
        for (var i = len - 1; i > 0; i--) {
          var movement = gaps[i - 1] * squeezePercent;
          shiftList(-movement, i, len);
        }
      }
    }

    function squeezeWhenBailout(delta) {
      var dir = delta < 0 ? -1 : 1;
      delta = Math.abs(delta);
      var moveForEachLabel = Math.ceil(delta / (len - 1));

      for (var i = 0; i < len - 1; i++) {
        if (dir > 0) {
          shiftList(moveForEachLabel, 0, i + 1);
        } else {
          shiftList(-moveForEachLabel, len - i - 1, len);
        }

        delta -= moveForEachLabel;

        if (delta <= 0) {
          return;
        }
      }
    }

    return adjusted;
  }

  function shiftLayoutOnX(list, leftBound, rightBound, balanceShift) {
    return shiftLayout(list, 'x', 'width', leftBound, rightBound, balanceShift);
  }

  function shiftLayoutOnY(list, topBound, bottomBound, balanceShift) {
    return shiftLayout(list, 'y', 'height', topBound, bottomBound, balanceShift);
  }

  function hideOverlap(labelList) {
    var displayedLabels = [];
    labelList.sort(function (a, b) {
      return b.priority - a.priority;
    });
    var globalRect = new BoundingRect(0, 0, 0, 0);

    for (var i = 0; i < labelList.length; i++) {
      var labelItem = labelList[i];
      var isAxisAligned = labelItem.axisAligned;
      var localRect = labelItem.localRect;
      var transform = labelItem.transform;
      var label = labelItem.label;
      var labelLine = labelItem.labelLine;
      globalRect.copy(labelItem.rect);
      globalRect.width -= 0.1;
      globalRect.height -= 0.1;
      globalRect.x += 0.05;
      globalRect.y += 0.05;
      var obb = labelItem.obb;
      var overlapped = false;

      for (var j = 0; j < displayedLabels.length; j++) {
        var existsTextCfg = displayedLabels[j];

        if (!globalRect.intersect(existsTextCfg.rect)) {
          continue;
        }

        if (isAxisAligned && existsTextCfg.axisAligned) {
          overlapped = true;
          break;
        }

        if (!existsTextCfg.obb) {
          existsTextCfg.obb = new OrientedBoundingRect(existsTextCfg.localRect, existsTextCfg.transform);
        }

        if (!obb) {
          obb = new OrientedBoundingRect(localRect, transform);
        }

        if (obb.intersect(existsTextCfg.obb)) {
          overlapped = true;
          break;
        }
      }

      if (overlapped) {
        label.hide();
        labelLine && labelLine.hide();
      } else {
        label.attr('ignore', labelItem.defaultAttr.ignore);
        labelLine && labelLine.attr('ignore', labelItem.defaultAttr.labelGuideIgnore);
        displayedLabels.push(labelItem);
      }
    }
  }

  function cloneArr(points) {
    if (points) {
      var newPoints = [];

      for (var i = 0; i < points.length; i++) {
        newPoints.push(points[i].slice());
      }

      return newPoints;
    }
  }

  function prepareLayoutCallbackParams(labelItem, hostEl) {
    var labelAttr = labelItem.defaultAttr;
    var label = labelItem.label;
    var labelLine = hostEl && hostEl.getTextGuideLine();
    return {
      dataIndex: labelItem.dataIndex,
      dataType: labelItem.dataType,
      seriesIndex: labelItem.seriesModel.seriesIndex,
      text: labelItem.label.style.text,
      rect: labelItem.hostRect,
      labelRect: labelAttr.rect,
      align: label.style.align,
      verticalAlign: label.style.verticalAlign,
      labelLinePoints: cloneArr(labelLine && labelLine.shape.points)
    };
  }

  var LABEL_OPTION_TO_STYLE_KEYS = ['align', 'verticalAlign', 'width', 'height', 'fontSize'];
  var dummyTransformable = new Transformable();
  var labelLayoutInnerStore = makeInner();
  var labelLineAnimationStore = makeInner();

  function extendWithKeys(target, source, keys) {
    for (var i = 0; i < keys.length; i++) {
      var key = keys[i];

      if (source[key] != null) {
        target[key] = source[key];
      }
    }
  }

  var LABEL_LAYOUT_PROPS = ['x', 'y', 'rotation'];

  var LabelManager = function () {
    function LabelManager() {
      this._labelList = [];
      this._chartViewList = [];
    }

    LabelManager.prototype.clearLabels = function () {
      this._labelList = [];
      this._chartViewList = [];
    };

    LabelManager.prototype._addLabel = function (dataIndex, dataType, seriesModel, label, layoutOption) {
      var labelStyle = label.style;
      var hostEl = label.__hostTarget;
      var textConfig = hostEl.textConfig || {};
      var labelTransform = label.getComputedTransform();
      var labelRect = label.getBoundingRect().plain();
      BoundingRect.applyTransform(labelRect, labelRect, labelTransform);

      if (labelTransform) {
        dummyTransformable.setLocalTransform(labelTransform);
      } else {
        dummyTransformable.x = dummyTransformable.y = dummyTransformable.rotation = dummyTransformable.originX = dummyTransformable.originY = 0;
        dummyTransformable.scaleX = dummyTransformable.scaleY = 1;
      }

      var host = label.__hostTarget;
      var hostRect;

      if (host) {
        hostRect = host.getBoundingRect().plain();
        var transform = host.getComputedTransform();
        BoundingRect.applyTransform(hostRect, hostRect, transform);
      }

      var labelGuide = hostRect && host.getTextGuideLine();

      this._labelList.push({
        label: label,
        labelLine: labelGuide,
        seriesModel: seriesModel,
        dataIndex: dataIndex,
        dataType: dataType,
        layoutOption: layoutOption,
        computedLayoutOption: null,
        hostRect: hostRect,
        priority: hostRect ? hostRect.width * hostRect.height : 0,
        defaultAttr: {
          ignore: label.ignore,
          labelGuideIgnore: labelGuide && labelGuide.ignore,
          x: dummyTransformable.x,
          y: dummyTransformable.y,
          rotation: dummyTransformable.rotation,
          rect: labelRect,
          style: {
            x: labelStyle.x,
            y: labelStyle.y,
            align: labelStyle.align,
            verticalAlign: labelStyle.verticalAlign,
            width: labelStyle.width,
            height: labelStyle.height,
            fontSize: labelStyle.fontSize
          },
          cursor: label.cursor,
          attachedPos: textConfig.position,
          attachedRot: textConfig.rotation
        }
      });
    };

    LabelManager.prototype.addLabelsOfSeries = function (chartView) {
      var _this = this;

      this._chartViewList.push(chartView);

      var seriesModel = chartView.__model;
      var layoutOption = seriesModel.get('labelLayout');

      if (!(isFunction(layoutOption) || keys(layoutOption).length)) {
        return;
      }

      chartView.group.traverse(function (child) {
        if (child.ignore) {
          return true;
        }

        var textEl = child.getTextContent();
        var ecData = getECData(child);
        var dataIndex = ecData.dataIndex;

        if (textEl && dataIndex != null && !textEl.disableLabelLayout) {
          _this._addLabel(dataIndex, ecData.dataType, seriesModel, textEl, layoutOption);
        }
      });
    };

    LabelManager.prototype.updateLayoutConfig = function (api) {
      var width = api.getWidth();
      var height = api.getHeight();

      function createDragHandler(el, labelLineModel) {
        return function () {
          updateLabelLinePoints(el, labelLineModel);
        };
      }

      for (var i = 0; i < this._labelList.length; i++) {
        var labelItem = this._labelList[i];
        var label = labelItem.label;
        var hostEl = label.__hostTarget;
        var defaultLabelAttr = labelItem.defaultAttr;
        var layoutOption = void 0;

        if (typeof labelItem.layoutOption === 'function') {
          layoutOption = labelItem.layoutOption(prepareLayoutCallbackParams(labelItem, hostEl));
        } else {
          layoutOption = labelItem.layoutOption;
        }

        layoutOption = layoutOption || {};
        labelItem.computedLayoutOption = layoutOption;
        var degreeToRadian = Math.PI / 180;

        if (hostEl) {
          hostEl.setTextConfig({
            local: false,
            position: layoutOption.x != null || layoutOption.y != null ? null : defaultLabelAttr.attachedPos,
            rotation: layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.attachedRot,
            offset: [layoutOption.dx || 0, layoutOption.dy || 0]
          });
        }

        var needsUpdateLabelLine = false;

        if (layoutOption.x != null) {
          label.x = parsePercent$2(layoutOption.x, width);
          label.setStyle('x', 0);
          needsUpdateLabelLine = true;
        } else {
          label.x = defaultLabelAttr.x;
          label.setStyle('x', defaultLabelAttr.style.x);
        }

        if (layoutOption.y != null) {
          label.y = parsePercent$2(layoutOption.y, height);
          label.setStyle('y', 0);
          needsUpdateLabelLine = true;
        } else {
          label.y = defaultLabelAttr.y;
          label.setStyle('y', defaultLabelAttr.style.y);
        }

        if (layoutOption.labelLinePoints) {
          var guideLine = hostEl.getTextGuideLine();

          if (guideLine) {
            guideLine.setShape({
              points: layoutOption.labelLinePoints
            });
            needsUpdateLabelLine = false;
          }
        }

        var labelLayoutStore = labelLayoutInnerStore(label);
        labelLayoutStore.needsUpdateLabelLine = needsUpdateLabelLine;
        label.rotation = layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.rotation;

        for (var k = 0; k < LABEL_OPTION_TO_STYLE_KEYS.length; k++) {
          var key = LABEL_OPTION_TO_STYLE_KEYS[k];
          label.setStyle(key, layoutOption[key] != null ? layoutOption[key] : defaultLabelAttr.style[key]);
        }

        if (layoutOption.draggable) {
          label.draggable = true;
          label.cursor = 'move';

          if (hostEl) {
            var data = labelItem.seriesModel.getData(labelItem.dataType);
            var itemModel = data.getItemModel(labelItem.dataIndex);
            label.on('drag', createDragHandler(hostEl, itemModel.getModel('labelLine')));
          }
        } else {
          label.off('drag');
          label.cursor = defaultLabelAttr.cursor;
        }
      }
    };

    LabelManager.prototype.layout = function (api) {
      var width = api.getWidth();
      var height = api.getHeight();
      var labelList = prepareLayoutList(this._labelList);
      var labelsNeedsAdjustOnX = filter(labelList, function (item) {
        return item.layoutOption.moveOverlap === 'shiftX';
      });
      var labelsNeedsAdjustOnY = filter(labelList, function (item) {
        return item.layoutOption.moveOverlap === 'shiftY';
      });
      shiftLayoutOnX(labelsNeedsAdjustOnX, 0, width);
      shiftLayoutOnY(labelsNeedsAdjustOnY, 0, height);
      var labelsNeedsHideOverlap = filter(labelList, function (item) {
        return item.layoutOption.hideOverlap;
      });
      hideOverlap(labelsNeedsHideOverlap);
    };

    LabelManager.prototype.processLabelsOverall = function () {
      var _this = this;

      each(this._chartViewList, function (chartView) {
        var seriesModel = chartView.__model;
        var ignoreLabelLineUpdate = chartView.ignoreLabelLineUpdate;
        var animationEnabled = seriesModel.isAnimationEnabled();
        chartView.group.traverse(function (child) {
          if (child.ignore) {
            return true;
          }

          var needsUpdateLabelLine = !ignoreLabelLineUpdate;
          var label = child.getTextContent();

          if (!needsUpdateLabelLine && label) {
            needsUpdateLabelLine = labelLayoutInnerStore(label).needsUpdateLabelLine;
          }

          if (needsUpdateLabelLine) {
            _this._updateLabelLine(child, seriesModel);
          }

          if (animationEnabled) {
            _this._animateLabels(child, seriesModel);
          }
        });
      });
    };

    LabelManager.prototype._updateLabelLine = function (el, seriesModel) {
      var textEl = el.getTextContent();
      var ecData = getECData(el);
      var dataIndex = ecData.dataIndex;

      if (textEl && dataIndex != null) {
        var data = seriesModel.getData(ecData.dataType);
        var itemModel = data.getItemModel(dataIndex);
        var defaultStyle = {};
        var visualStyle = data.getItemVisual(dataIndex, 'style');
        var visualType = data.getVisual('drawType');
        defaultStyle.stroke = visualStyle[visualType];
        var labelLineModel = itemModel.getModel('labelLine');
        setLabelLineStyle(el, getLabelLineStatesModels(itemModel), defaultStyle);
        updateLabelLinePoints(el, labelLineModel);
      }
    };

    LabelManager.prototype._animateLabels = function (el, seriesModel) {
      var textEl = el.getTextContent();
      var guideLine = el.getTextGuideLine();

      if (textEl && !textEl.ignore && !textEl.invisible && !el.disableLabelAnimation) {
        var layoutStore = labelLayoutInnerStore(textEl);
        var oldLayout = layoutStore.oldLayout;
        var newProps = {
          x: textEl.x,
          y: textEl.y,
          rotation: textEl.rotation
        };

        if (!oldLayout) {
          textEl.attr(newProps);
          var oldOpacity = retrieve2(textEl.style.opacity, 1);
          textEl.style.opacity = 0;
          initProps(textEl, {
            style: {
              opacity: oldOpacity
            }
          }, seriesModel);
        } else {
          textEl.attr(oldLayout);
          var prevStates = el.prevStates;

          if (prevStates) {
            if (indexOf(prevStates, 'select') >= 0) {
              textEl.attr(layoutStore.oldLayoutSelect);
            }

            if (indexOf(prevStates, 'emphasis') >= 0) {
              textEl.attr(layoutStore.oldLayoutEmphasis);
            }
          }

          updateProps(textEl, newProps, seriesModel);
        }

        layoutStore.oldLayout = newProps;

        if (textEl.states.select) {
          var layoutSelect = layoutStore.oldLayoutSelect = {};
          extendWithKeys(layoutSelect, newProps, LABEL_LAYOUT_PROPS);
          extendWithKeys(layoutSelect, textEl.states.select, LABEL_LAYOUT_PROPS);
        }

        if (textEl.states.emphasis) {
          var layoutEmphasis = layoutStore.oldLayoutEmphasis = {};
          extendWithKeys(layoutEmphasis, newProps, LABEL_LAYOUT_PROPS);
          extendWithKeys(layoutEmphasis, textEl.states.emphasis, LABEL_LAYOUT_PROPS);
        }
      }

      if (guideLine && !guideLine.ignore && !guideLine.invisible) {
        var layoutStore = labelLineAnimationStore(guideLine);
        var oldLayout = layoutStore.oldLayout;
        var newLayout = {
          points: guideLine.shape.points
        };

        if (!oldLayout) {
          guideLine.setShape(newLayout);
          guideLine.style.strokePercent = 0;
          initProps(guideLine, {
            style: {
              strokePercent: 1
            }
          }, seriesModel);
        } else {
          guideLine.attr({
            shape: oldLayout
          });
          updateProps(guideLine, {
            shape: newLayout
          }, seriesModel);
        }

        layoutStore.oldLayout = newLayout;
      }
    };

    return LabelManager;
  }();

  function createLegacyDataSelectAction(seriesType, ecRegisterAction) {
    function getSeriesIndices(ecModel, payload) {
      var seriesIndices = [];
      ecModel.eachComponent({
        mainType: 'series',
        subType: seriesType,
        query: payload
      }, function (seriesModel) {
        seriesIndices.push(seriesModel.seriesIndex);
      });
      return seriesIndices;
    }

    each([[seriesType + 'ToggleSelect', 'toggleSelect'], [seriesType + 'Select', 'select'], [seriesType + 'UnSelect', 'unselect']], function (eventsMap) {
      ecRegisterAction(eventsMap[0], function (payload, ecModel, api) {
        payload = extend({}, payload);

        if (true) {
          deprecateReplaceLog(payload.type, eventsMap[1]);
        }

        api.dispatchAction(extend(payload, {
          type: eventsMap[1],
          seriesIndex: getSeriesIndices(ecModel, payload)
        }));
      });
    });
  }

  function handleSeriesLegacySelectEvents(type, eventPostfix, ecIns, payload) {
    var legacyEventName = type + eventPostfix;

    if (!ecIns.isSilent(legacyEventName)) {
      if (true) {
        deprecateLog("event " + legacyEventName + " is deprecated.");
      }

      var ecModel = ecIns.getModel();
      ecModel.eachComponent({
        mainType: 'series',
        subType: 'pie'
      }, function (seriesModel) {
        var seriesIndex = seriesModel.seriesIndex;
        var selected = payload.selected;

        for (var i = 0; i < selected.length; i++) {
          if (selected[i].seriesIndex === seriesIndex) {
            var data = seriesModel.getData();
            var dataIndex = queryDataIndex(data, payload.fromActionPayload);
            ecIns.trigger(legacyEventName, {
              type: legacyEventName,
              seriesId: seriesModel.id,
              name: isArray(dataIndex) ? data.getName(dataIndex[0]) : data.getName(dataIndex),
              selected: extend({}, seriesModel.option.selectedMap)
            });
          }
        }
      });
    }
  }

  function handleLegacySelectEvents(messageCenter, ecIns) {
    messageCenter.on('selectchanged', function (params) {
      if (params.isFromClick) {
        handleSeriesLegacySelectEvents('map', 'selectchanged', ecIns, params);
        handleSeriesLegacySelectEvents('pie', 'selectchanged', ecIns, params);
      } else if (params.fromAction === 'select') {
        handleSeriesLegacySelectEvents('map', 'selected', ecIns, params);
        handleSeriesLegacySelectEvents('pie', 'selected', ecIns, params);
      } else if (params.fromAction === 'unselect') {
        handleSeriesLegacySelectEvents('map', 'unselected', ecIns, params);
        handleSeriesLegacySelectEvents('pie', 'unselected', ecIns, params);
      }
    });
  }

  function createLinearGradient(ctx, obj, rect) {
    var x = obj.x == null ? 0 : obj.x;
    var x2 = obj.x2 == null ? 1 : obj.x2;
    var y = obj.y == null ? 0 : obj.y;
    var y2 = obj.y2 == null ? 0 : obj.y2;

    if (!obj.global) {
      x = x * rect.width + rect.x;
      x2 = x2 * rect.width + rect.x;
      y = y * rect.height + rect.y;
      y2 = y2 * rect.height + rect.y;
    }

    x = isNaN(x) ? 0 : x;
    x2 = isNaN(x2) ? 1 : x2;
    y = isNaN(y) ? 0 : y;
    y2 = isNaN(y2) ? 0 : y2;
    var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);
    return canvasGradient;
  }

  function createRadialGradient(ctx, obj, rect) {
    var width = rect.width;
    var height = rect.height;
    var min = Math.min(width, height);
    var x = obj.x == null ? 0.5 : obj.x;
    var y = obj.y == null ? 0.5 : obj.y;
    var r = obj.r == null ? 0.5 : obj.r;

    if (!obj.global) {
      x = x * width + rect.x;
      y = y * height + rect.y;
      r = r * min;
    }

    var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);
    return canvasGradient;
  }

  function getCanvasGradient(ctx, obj, rect) {
    var canvasGradient = obj.type === 'radial' ? createRadialGradient(ctx, obj, rect) : createLinearGradient(ctx, obj, rect);
    var colorStops = obj.colorStops;

    for (var i = 0; i < colorStops.length; i++) {
      canvasGradient.addColorStop(colorStops[i].offset, colorStops[i].color);
    }

    return canvasGradient;
  }

  var pathProxyForDraw = new PathProxy(true);

  function styleHasStroke(style) {
    var stroke = style.stroke;
    return !(stroke == null || stroke === 'none' || !(style.lineWidth > 0));
  }

  function styleHasFill(style) {
    var fill = style.fill;
    return fill != null && fill !== 'none';
  }

  function doFillPath(ctx, style) {
    if (style.fillOpacity != null && style.fillOpacity !== 1) {
      var originalGlobalAlpha = ctx.globalAlpha;
      ctx.globalAlpha = style.fillOpacity * style.opacity;
      ctx.fill();
      ctx.globalAlpha = originalGlobalAlpha;
    } else {
      ctx.fill();
    }
  }

  function doStrokePath(ctx, style) {
    if (style.strokeOpacity != null && style.strokeOpacity !== 1) {
      var originalGlobalAlpha = ctx.globalAlpha;
      ctx.globalAlpha = style.strokeOpacity * style.opacity;
      ctx.stroke();
      ctx.globalAlpha = originalGlobalAlpha;
    } else {
      ctx.stroke();
    }
  }

  function createCanvasPattern(ctx, pattern, el) {
    var image = createOrUpdateImage(pattern.image, pattern.__image, el);

    if (isImageReady(image)) {
      return ctx.createPattern(image, pattern.repeat || 'repeat');
    }
  }

  function brushPath(ctx, el, style, inBatch) {
    var hasStroke = styleHasStroke(style);
    var hasFill = styleHasFill(style);
    var strokePercent = style.strokePercent;
    var strokePart = strokePercent < 1;
    var firstDraw = !el.path;

    if ((!el.silent || strokePart) && firstDraw) {
      el.createPathProxy();
    }

    var path = el.path || pathProxyForDraw;

    if (!inBatch) {
      var fill = style.fill;
      var stroke = style.stroke;
      var hasFillGradient = hasFill && !!fill.colorStops;
      var hasStrokeGradient = hasStroke && !!stroke.colorStops;
      var hasFillPattern = hasFill && !!fill.image;
      var hasStrokePattern = hasStroke && !!stroke.image;
      var fillGradient = void 0;
      var strokeGradient = void 0;
      var fillPattern = void 0;
      var strokePattern = void 0;
      var rect = void 0;

      if (hasFillGradient || hasStrokeGradient) {
        rect = el.getBoundingRect();
      }

      if (hasFillGradient) {
        fillGradient = el.__dirty ? getCanvasGradient(ctx, fill, rect) : el.__canvasFillGradient;
        el.__canvasFillGradient = fillGradient;
      }

      if (hasStrokeGradient) {
        strokeGradient = el.__dirty ? getCanvasGradient(ctx, stroke, rect) : el.__canvasStrokeGradient;
        el.__canvasStrokeGradient = strokeGradient;
      }

      if (hasFillPattern) {
        fillPattern = el.__dirty || !el.__canvasFillPattern ? createCanvasPattern(ctx, fill, el) : el.__canvasFillPattern;
        el.__canvasFillPattern = fillPattern;
      }

      if (hasStrokePattern) {
        strokePattern = el.__dirty || !el.__canvasStrokePattern ? createCanvasPattern(ctx, stroke, el) : el.__canvasStrokePattern;
        el.__canvasStrokePattern = fillPattern;
      }

      if (hasFillGradient) {
        ctx.fillStyle = fillGradient;
      } else if (hasFillPattern) {
        if (fillPattern) {
          ctx.fillStyle = fillPattern;
        } else {
          hasFill = false;
        }
      }

      if (hasStrokeGradient) {
        ctx.strokeStyle = strokeGradient;
      } else if (hasStrokePattern) {
        if (strokePattern) {
          ctx.strokeStyle = strokePattern;
        } else {
          hasStroke = false;
        }
      }
    }

    var lineDash = style.lineDash;
    var lineDashOffset = style.lineDashOffset;
    var ctxLineDash = !!ctx.setLineDash;
    var scale = el.getGlobalScale();
    path.setScale(scale[0], scale[1], el.segmentIgnoreThreshold);

    if (lineDash) {
      var lineScale_1 = style.strokeNoScale && el.getLineScale ? el.getLineScale() : 1;

      if (lineScale_1 && lineScale_1 !== 1) {
        lineDash = map(lineDash, function (rawVal) {
          return rawVal / lineScale_1;
        });
        lineDashOffset /= lineScale_1;
      }
    }

    var needsRebuild = true;

    if (firstDraw || el.__dirty & Path.SHAPE_CHANGED_BIT || lineDash && !ctxLineDash && hasStroke) {
      path.setDPR(ctx.dpr);

      if (strokePart) {
        path.setContext(null);
      } else {
        path.setContext(ctx);
        needsRebuild = false;
      }

      path.reset();

      if (lineDash && !ctxLineDash) {
        path.setLineDash(lineDash);
        path.setLineDashOffset(lineDashOffset);
      }

      el.buildPath(path, el.shape, inBatch);
      path.toStatic();
      el.pathUpdated();
    }

    if (needsRebuild) {
      path.rebuildPath(ctx, strokePart ? strokePercent : 1);
    }

    if (lineDash && ctxLineDash) {
      ctx.setLineDash(lineDash);
      ctx.lineDashOffset = lineDashOffset;
    }

    if (!inBatch) {
      if (style.strokeFirst) {
        if (hasStroke) {
          doStrokePath(ctx, style);
        }

        if (hasFill) {
          doFillPath(ctx, style);
        }
      } else {
        if (hasFill) {
          doFillPath(ctx, style);
        }

        if (hasStroke) {
          doStrokePath(ctx, style);
        }
      }
    }

    if (lineDash && ctxLineDash) {
      ctx.setLineDash([]);
    }
  }

  function brushImage(ctx, el, style) {
    var image = el.__image = createOrUpdateImage(style.image, el.__image, el, el.onload);

    if (!image || !isImageReady(image)) {
      return;
    }

    var x = style.x || 0;
    var y = style.y || 0;
    var width = style.width;
    var height = style.height;
    var aspect = image.width / image.height;

    if (width == null && height != null) {
      width = height * aspect;
    } else if (height == null && width != null) {
      height = width / aspect;
    } else if (width == null && height == null) {
      width = image.width;
      height = image.height;
    }

    if (style.sWidth && style.sHeight) {
      var sx = style.sx || 0;
      var sy = style.sy || 0;
      ctx.drawImage(image, sx, sy, style.sWidth, style.sHeight, x, y, width, height);
    } else if (style.sx && style.sy) {
      var sx = style.sx;
      var sy = style.sy;
      var sWidth = width - sx;
      var sHeight = height - sy;
      ctx.drawImage(image, sx, sy, sWidth, sHeight, x, y, width, height);
    } else {
      ctx.drawImage(image, x, y, width, height);
    }
  }

  function brushText(ctx, el, style) {
    var text = style.text;
    text != null && (text += '');

    if (text) {
      ctx.font = style.font || DEFAULT_FONT;
      ctx.textAlign = style.textAlign;
      ctx.textBaseline = style.textBaseline;

      if (ctx.setLineDash) {
        var lineDash = style.lineDash;
        var lineDashOffset = style.lineDashOffset;

        if (lineDash) {
          var lineScale_2 = style.strokeNoScale && el.getLineScale ? el.getLineScale() : 1;

          if (lineScale_2 && lineScale_2 !== 1) {
            lineDash = map(lineDash, function (rawVal) {
              return rawVal / lineScale_2;
            });
            lineDashOffset /= lineScale_2;
          }
        }

        ctx.setLineDash(lineDash || []);
        ctx.lineDashOffset = lineDashOffset;
      }

      if (style.strokeFirst) {
        if (styleHasStroke(style)) {
          ctx.strokeText(text, style.x, style.y);
        }

        if (styleHasFill(style)) {
          ctx.fillText(text, style.x, style.y);
        }
      } else {
        if (styleHasFill(style)) {
          ctx.fillText(text, style.x, style.y);
        }

        if (styleHasStroke(style)) {
          ctx.strokeText(text, style.x, style.y);
        }
      }
    }
  }

  var SHADOW_NUMBER_PROPS = ['shadowBlur', 'shadowOffsetX', 'shadowOffsetY'];
  var STROKE_PROPS = [['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]];

  function bindCommonProps(ctx, style, prevStyle, forceSetAll, scope) {
    var styleChanged = false;

    if (!forceSetAll) {
      prevStyle = prevStyle || {};

      if (style === prevStyle) {
        return false;
      }
    }

    if (forceSetAll || style.opacity !== prevStyle.opacity) {
      if (!styleChanged) {
        flushPathDrawn(ctx, scope);
        styleChanged = true;
      }

      ctx.globalAlpha = style.opacity == null ? DEFAULT_COMMON_STYLE.opacity : style.opacity;
    }

    if (forceSetAll || style.blend !== prevStyle.blend) {
      if (!styleChanged) {
        flushPathDrawn(ctx, scope);
        styleChanged = true;
      }

      ctx.globalCompositeOperation = style.blend || DEFAULT_COMMON_STYLE.blend;
    }

    for (var i = 0; i < SHADOW_NUMBER_PROPS.length; i++) {
      var propName = SHADOW_NUMBER_PROPS[i];

      if (forceSetAll || style[propName] !== prevStyle[propName]) {
        if (!styleChanged) {
          flushPathDrawn(ctx, scope);
          styleChanged = true;
        }

        ctx[propName] = ctx.dpr * (style[propName] || 0);
      }
    }

    if (forceSetAll || style.shadowColor !== prevStyle.shadowColor) {
      if (!styleChanged) {
        flushPathDrawn(ctx, scope);
        styleChanged = true;
      }

      ctx.shadowColor = style.shadowColor || DEFAULT_COMMON_STYLE.shadowColor;
    }

    return styleChanged;
  }

  function bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetAll, scope) {
    var style = getStyle(el, scope.inHover);
    var prevStyle = forceSetAll ? null : prevEl && getStyle(prevEl, scope.inHover) || {};

    if (style === prevStyle) {
      return false;
    }

    var styleChanged = bindCommonProps(ctx, style, prevStyle, forceSetAll, scope);

    if (forceSetAll || style.fill !== prevStyle.fill) {
      if (!styleChanged) {
        flushPathDrawn(ctx, scope);
        styleChanged = true;
      }

      ctx.fillStyle = style.fill;
    }

    if (forceSetAll || style.stroke !== prevStyle.stroke) {
      if (!styleChanged) {
        flushPathDrawn(ctx, scope);
        styleChanged = true;
      }

      ctx.strokeStyle = style.stroke;
    }

    if (forceSetAll || style.opacity !== prevStyle.opacity) {
      if (!styleChanged) {
        flushPathDrawn(ctx, scope);
        styleChanged = true;
      }

      ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;
    }

    if (el.hasStroke()) {
      var lineWidth = style.lineWidth;
      var newLineWidth = lineWidth / (style.strokeNoScale && el && el.getLineScale ? el.getLineScale() : 1);

      if (ctx.lineWidth !== newLineWidth) {
        if (!styleChanged) {
          flushPathDrawn(ctx, scope);
          styleChanged = true;
        }

        ctx.lineWidth = newLineWidth;
      }
    }

    for (var i = 0; i < STROKE_PROPS.length; i++) {
      var prop = STROKE_PROPS[i];
      var propName = prop[0];

      if (forceSetAll || style[propName] !== prevStyle[propName]) {
        if (!styleChanged) {
          flushPathDrawn(ctx, scope);
          styleChanged = true;
        }

        ctx[propName] = style[propName] || prop[1];
      }
    }

    return styleChanged;
  }

  function bindImageStyle(ctx, el, prevEl, forceSetAll, scope) {
    return bindCommonProps(ctx, getStyle(el, scope.inHover), prevEl && getStyle(prevEl, scope.inHover), forceSetAll, scope);
  }

  function setContextTransform(ctx, el) {
    var m = el.transform;
    var dpr = ctx.dpr || 1;

    if (m) {
      ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);
    } else {
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    }
  }

  var tmpRect = new BoundingRect(0, 0, 0, 0);
  var viewRect = new BoundingRect(0, 0, 0, 0);

  function isDisplayableCulled(el, width, height) {
    tmpRect.copy(el.getBoundingRect());

    if (el.transform) {
      tmpRect.applyTransform(el.transform);
    }

    viewRect.width = width;
    viewRect.height = height;
    return !tmpRect.intersect(viewRect);
  }

  function isClipPathChanged(clipPaths, prevClipPaths) {
    if (clipPaths === prevClipPaths || !clipPaths && !prevClipPaths) {
      return false;
    }

    if (!clipPaths || !prevClipPaths || clipPaths.length !== prevClipPaths.length) {
      return true;
    }

    for (var i = 0; i < clipPaths.length; i++) {
      if (clipPaths[i] !== prevClipPaths[i]) {
        return true;
      }
    }

    return false;
  }

  function updateClipStatus(clipPaths, ctx, scope) {
    var allClipped = false;

    for (var i = 0; i < clipPaths.length; i++) {
      var clipPath = clipPaths[i];
      allClipped = allClipped || clipPath.isZeroArea();
      setContextTransform(ctx, clipPath);
      ctx.beginPath();
      clipPath.buildPath(ctx, clipPath.shape);
      ctx.clip();
    }

    scope.allClipped = allClipped;
  }

  function isTransformChanged(m0, m1) {
    if (m0 && m1) {
      return m0[0] !== m1[0] || m0[1] !== m1[1] || m0[2] !== m1[2] || m0[3] !== m1[3] || m0[4] !== m1[4] || m0[5] !== m1[5];
    } else if (!m0 && !m1) {
      return false;
    }

    return true;
  }

  var DRAW_TYPE_PATH = 1;
  var DRAW_TYPE_IMAGE = 2;
  var DRAW_TYPE_TEXT = 3;
  var DRAW_TYPE_INCREMENTAL = 4;

  function canPathBatch(style) {
    var hasFill = styleHasFill(style);
    var hasStroke = styleHasStroke(style);
    return !(style.lineDash || !(+hasFill ^ +hasStroke) || hasFill && typeof style.fill !== 'string' || hasStroke && typeof style.stroke !== 'string' || style.strokePercent < 1 || style.strokeOpacity < 1 || style.fillOpacity < 1);
  }

  function flushPathDrawn(ctx, scope) {
    scope.batchFill && ctx.fill();
    scope.batchStroke && ctx.stroke();
    scope.batchFill = '';
    scope.batchStroke = '';
  }

  function getStyle(el, inHover) {
    return inHover ? el.__hoverStyle || el.style : el.style;
  }

  function brush(ctx, el, scope, isLast) {
    var m = el.transform;

    if (el.invisible || el.style.opacity === 0 || el.culling && isDisplayableCulled(el, scope.viewWidth, scope.viewHeight) || m && !m[0] && !m[3]) {
      el.__dirty = 0;
      return;
    }

    var clipPaths = el.__clipPaths;
    var prevElClipPaths = scope.prevElClipPaths;
    var forceSetTransform = false;
    var forceSetStyle = false;

    if (!prevElClipPaths || isClipPathChanged(clipPaths, prevElClipPaths)) {
      if (prevElClipPaths && prevElClipPaths.length) {
        flushPathDrawn(ctx, scope);
        ctx.restore();
        forceSetStyle = forceSetTransform = true;
        scope.prevElClipPaths = null;
        scope.allClipped = false;
        scope.prevEl = null;
      }

      if (clipPaths && clipPaths.length) {
        flushPathDrawn(ctx, scope);
        ctx.save();
        updateClipStatus(clipPaths, ctx, scope);
        forceSetTransform = true;
      }

      scope.prevElClipPaths = clipPaths;
    }

    if (scope.allClipped) {
      return;
    }

    el.beforeBrush && el.beforeBrush();
    el.innerBeforeBrush();
    var prevEl = scope.prevEl;

    if (!prevEl) {
      forceSetStyle = forceSetTransform = true;
    }

    var canBatchPath = el instanceof Path && el.autoBatch && canPathBatch(el.style);

    if (forceSetTransform || isTransformChanged(m, prevEl.transform)) {
      flushPathDrawn(ctx, scope);
      setContextTransform(ctx, el);
    } else if (!canBatchPath) {
      flushPathDrawn(ctx, scope);
    }

    var style = getStyle(el, scope.inHover);

    if (el instanceof Path) {
      if (scope.lastDrawType !== DRAW_TYPE_PATH) {
        forceSetStyle = true;
        scope.lastDrawType = DRAW_TYPE_PATH;
      }

      bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetStyle, scope);

      if (!canBatchPath || !scope.batchFill && !scope.batchStroke) {
        ctx.beginPath();
      }

      brushPath(ctx, el, style, canBatchPath);

      if (canBatchPath) {
        scope.batchFill = style.fill || '';
        scope.batchStroke = style.stroke || '';
      }
    } else {
      if (el instanceof TSpan) {
        if (scope.lastDrawType !== DRAW_TYPE_TEXT) {
          forceSetStyle = true;
          scope.lastDrawType = DRAW_TYPE_TEXT;
        }

        bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetStyle, scope);
        brushText(ctx, el, style);
      } else if (el instanceof ZRImage) {
        if (scope.lastDrawType !== DRAW_TYPE_IMAGE) {
          forceSetStyle = true;
          scope.lastDrawType = DRAW_TYPE_IMAGE;
        }

        bindImageStyle(ctx, el, prevEl, forceSetStyle, scope);
        brushImage(ctx, el, style);
      } else if (el instanceof IncrementalDisplayble) {
        if (scope.lastDrawType !== DRAW_TYPE_INCREMENTAL) {
          forceSetStyle = true;
          scope.lastDrawType = DRAW_TYPE_INCREMENTAL;
        }

        brushIncremental(ctx, el, scope);
      }
    }

    if (canBatchPath && isLast) {
      flushPathDrawn(ctx, scope);
    }

    el.innerAfterBrush();
    el.afterBrush && el.afterBrush();
    scope.prevEl = el;
    el.__dirty = 0;
  }

  function brushIncremental(ctx, el, scope) {
    var displayables = el.getDisplayables();
    var temporalDisplayables = el.getTemporalDisplayables();
    ctx.save();
    var innerScope = {
      prevElClipPaths: null,
      prevEl: null,
      allClipped: false,
      viewWidth: scope.viewWidth,
      viewHeight: scope.viewHeight,
      inHover: scope.inHover
    };
    var i;
    var len;

    for (i = el.getCursor(), len = displayables.length; i < len; i++) {
      var displayable = displayables[i];
      displayable.beforeBrush && displayable.beforeBrush();
      displayable.innerBeforeBrush();
      brush(ctx, displayable, innerScope, i === len - 1);
      displayable.innerAfterBrush();
      displayable.afterBrush && displayable.afterBrush();
      innerScope.prevEl = displayable;
    }

    for (var i_1 = 0, len_1 = temporalDisplayables.length - 1; i_1 < len_1; i_1++) {
      var displayable = temporalDisplayables[i_1];
      displayable.beforeBrush && displayable.beforeBrush();
      displayable.innerBeforeBrush();
      brush(ctx, displayable, innerScope, i_1 === len_1 - 1);
      displayable.innerAfterBrush();
      displayable.afterBrush && displayable.afterBrush();
      innerScope.prevEl = displayable;
    }

    el.clearTemporalDisplayables();
    el.notClear = true;
    ctx.restore();
  }

  function returnFalse() {
    return false;
  }

  function createDom(id, painter, dpr) {
    var newDom = createCanvas();
    var width = painter.getWidth();
    var height = painter.getHeight();
    var newDomStyle = newDom.style;

    if (newDomStyle) {
      newDomStyle.position = 'absolute';
      newDomStyle.left = '0';
      newDomStyle.top = '0';
      newDomStyle.width = width + 'px';
      newDomStyle.height = height + 'px';
      newDom.setAttribute('data-zr-dom-id', id);
    }

    newDom.width = width * dpr;
    newDom.height = height * dpr;
    return newDom;
  }

  var Layer = function (_super) {
    __extends(Layer, _super);

    function Layer(id, painter, dpr) {
      var _this = _super.call(this) || this;

      _this.motionBlur = false;
      _this.lastFrameAlpha = 0.7;
      _this.dpr = 1;
      _this.virtual = false;
      _this.config = {};
      _this.incremental = false;
      _this.zlevel = 0;
      _this.__dirty = true;
      _this.__used = false;
      _this.__drawIndex = 0;
      _this.__startIndex = 0;
      _this.__endIndex = 0;
      var dom;
      dpr = dpr || devicePixelRatio;

      if (typeof id === 'string') {
        dom = createDom(id, painter, dpr);
      } else if (isObject(id)) {
        dom = id;
        id = dom.id;
      }

      _this.id = id;
      _this.dom = dom;
      var domStyle = dom.style;

      if (domStyle) {
        dom.onselectstart = returnFalse;
        domStyle.webkitUserSelect = 'none';
        domStyle.userSelect = 'none';
        domStyle.webkitTapHighlightColor = 'rgba(0,0,0,0)';
        domStyle['-webkit-touch-callout'] = 'none';
        domStyle.padding = '0';
        domStyle.margin = '0';
        domStyle.borderWidth = '0';
      }

      _this.domBack = null;
      _this.ctxBack = null;
      _this.painter = painter;
      _this.config = null;
      _this.dpr = dpr;
      return _this;
    }

    Layer.prototype.getElementCount = function () {
      return this.__endIndex - this.__startIndex;
    };

    Layer.prototype.initContext = function () {
      this.ctx = this.dom.getContext('2d');
      this.ctx.dpr = this.dpr;
    };

    Layer.prototype.createBackBuffer = function () {
      var dpr = this.dpr;
      this.domBack = createDom('back-' + this.id, this.painter, dpr);
      this.ctxBack = this.domBack.getContext('2d');

      if (dpr !== 1) {
        this.ctxBack.scale(dpr, dpr);
      }
    };

    Layer.prototype.resize = function (width, height) {
      var dpr = this.dpr;
      var dom = this.dom;
      var domStyle = dom.style;
      var domBack = this.domBack;

      if (domStyle) {
        domStyle.width = width + 'px';
        domStyle.height = height + 'px';
      }

      dom.width = width * dpr;
      dom.height = height * dpr;

      if (domBack) {
        domBack.width = width * dpr;
        domBack.height = height * dpr;

        if (dpr !== 1) {
          this.ctxBack.scale(dpr, dpr);
        }
      }
    };

    Layer.prototype.clear = function (clearAll, clearColor) {
      var dom = this.dom;
      var ctx = this.ctx;
      var width = dom.width;
      var height = dom.height;
      clearColor = clearColor || this.clearColor;
      var haveMotionBLur = this.motionBlur && !clearAll;
      var lastFrameAlpha = this.lastFrameAlpha;
      var dpr = this.dpr;
      var self = this;

      if (haveMotionBLur) {
        if (!this.domBack) {
          this.createBackBuffer();
        }

        this.ctxBack.globalCompositeOperation = 'copy';
        this.ctxBack.drawImage(dom, 0, 0, width / dpr, height / dpr);
      }

      ctx.clearRect(0, 0, width, height);

      if (clearColor && clearColor !== 'transparent') {
        var clearColorGradientOrPattern = void 0;

        if (isGradientObject(clearColor)) {
          clearColorGradientOrPattern = clearColor.__canvasGradient || getCanvasGradient(ctx, clearColor, {
            x: 0,
            y: 0,
            width: width,
            height: height
          });
          clearColor.__canvasGradient = clearColorGradientOrPattern;
        } else if (isPatternObject(clearColor)) {
          clearColorGradientOrPattern = createCanvasPattern(ctx, clearColor, {
            dirty: function () {
              self.__painter.refresh();
            }
          });
        }

        ctx.save();
        ctx.fillStyle = clearColorGradientOrPattern || clearColor;
        ctx.fillRect(0, 0, width, height);
        ctx.restore();
      }

      if (haveMotionBLur) {
        var domBack = this.domBack;
        ctx.save();
        ctx.globalAlpha = lastFrameAlpha;
        ctx.drawImage(domBack, 0, 0, width, height);
        ctx.restore();
      }
    };

    return Layer;
  }(Eventful);

  var HOVER_LAYER_ZLEVEL = 1e5;
  var CANVAS_ZLEVEL = 314159;
  var EL_AFTER_INCREMENTAL_INC = 0.01;
  var INCREMENTAL_INC = 0.001;

  function parseInt10(val) {
    return parseInt(val, 10);
  }

  function isLayerValid(layer) {
    if (!layer) {
      return false;
    }

    if (layer.__builtin__) {
      return true;
    }

    if (typeof layer.resize !== 'function' || typeof layer.refresh !== 'function') {
      return false;
    }

    return true;
  }

  function createRoot(width, height) {
    var domRoot = document.createElement('div');
    domRoot.style.cssText = ['position:relative', 'width:' + width + 'px', 'height:' + height + 'px', 'padding:0', 'margin:0', 'border-width:0'].join(';') + ';';
    return domRoot;
  }

  var CanvasPainter = function () {
    function CanvasPainter(root, storage, opts, id) {
      this.type = 'canvas';
      this._zlevelList = [];
      this._layers = {};
      this._layerConfig = {};
      this._needsManuallyCompositing = false;
      this.type = 'canvas';
      var singleCanvas = !root.nodeName || root.nodeName.toUpperCase() === 'CANVAS';
      this._opts = opts = extend({}, opts || {});
      this.dpr = opts.devicePixelRatio || devicePixelRatio;
      this._singleCanvas = singleCanvas;
      this.root = root;
      var rootStyle = root.style;

      if (rootStyle) {
        rootStyle.webkitTapHighlightColor = 'transparent';
        rootStyle.webkitUserSelect = 'none';
        rootStyle.userSelect = 'none';
        rootStyle['-webkit-touch-callout'] = 'none';
        root.innerHTML = '';
      }

      this.storage = storage;
      var zlevelList = this._zlevelList;
      var layers = this._layers;

      if (!singleCanvas) {
        this._width = this._getSize(0);
        this._height = this._getSize(1);
        var domRoot = this._domRoot = createRoot(this._width, this._height);
        root.appendChild(domRoot);
      } else {
        var rootCanvas = root;
        var width = rootCanvas.width;
        var height = rootCanvas.height;

        if (opts.width != null) {
          width = opts.width;
        }

        if (opts.height != null) {
          height = opts.height;
        }

        this.dpr = opts.devicePixelRatio || 1;
        rootCanvas.width = width * this.dpr;
        rootCanvas.height = height * this.dpr;
        this._width = width;
        this._height = height;
        var mainLayer = new Layer(rootCanvas, this, this.dpr);
        mainLayer.__builtin__ = true;
        mainLayer.initContext();
        layers[CANVAS_ZLEVEL] = mainLayer;
        mainLayer.zlevel = CANVAS_ZLEVEL;
        zlevelList.push(CANVAS_ZLEVEL);
        this._domRoot = root;
      }
    }

    CanvasPainter.prototype.getType = function () {
      return 'canvas';
    };

    CanvasPainter.prototype.isSingleCanvas = function () {
      return this._singleCanvas;
    };

    CanvasPainter.prototype.getViewportRoot = function () {
      return this._domRoot;
    };

    CanvasPainter.prototype.getViewportRootOffset = function () {
      var viewportRoot = this.getViewportRoot();

      if (viewportRoot) {
        return {
          offsetLeft: viewportRoot.offsetLeft || 0,
          offsetTop: viewportRoot.offsetTop || 0
        };
      }
    };

    CanvasPainter.prototype.refresh = function (paintAll) {
      var list = this.storage.getDisplayList(true);
      var zlevelList = this._zlevelList;
      this._redrawId = Math.random();

      this._paintList(list, paintAll, this._redrawId);

      for (var i = 0; i < zlevelList.length; i++) {
        var z = zlevelList[i];
        var layer = this._layers[z];

        if (!layer.__builtin__ && layer.refresh) {
          var clearColor = i === 0 ? this._backgroundColor : null;
          layer.refresh(clearColor);
        }
      }

      return this;
    };

    CanvasPainter.prototype.refreshHover = function () {
      this._paintHoverList(this.storage.getDisplayList(false));
    };

    CanvasPainter.prototype._paintHoverList = function (list) {
      var len = list.length;
      var hoverLayer = this._hoverlayer;
      hoverLayer && hoverLayer.clear();

      if (!len) {
        return;
      }

      var scope = {
        inHover: true,
        viewWidth: this._width,
        viewHeight: this._height
      };
      var ctx;

      for (var i = 0; i < len; i++) {
        var el = list[i];

        if (el.__inHover) {
          if (!hoverLayer) {
            hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL);
          }

          if (!ctx) {
            ctx = hoverLayer.ctx;
            ctx.save();
          }

          brush(ctx, el, scope, i === len - 1);
        }
      }

      if (ctx) {
        ctx.restore();
      }
    };

    CanvasPainter.prototype.getHoverLayer = function () {
      return this.getLayer(HOVER_LAYER_ZLEVEL);
    };

    CanvasPainter.prototype._paintList = function (list, paintAll, redrawId) {
      if (this._redrawId !== redrawId) {
        return;
      }

      paintAll = paintAll || false;

      this._updateLayerStatus(list);

      var _a = this._doPaintList(list, paintAll),
          finished = _a.finished,
          needsRefreshHover = _a.needsRefreshHover;

      if (this._needsManuallyCompositing) {
        this._compositeManually();
      }

      if (needsRefreshHover) {
        this._paintHoverList(list);
      }

      if (!finished) {
        var self_1 = this;
        requestAnimationFrame$1(function () {
          self_1._paintList(list, paintAll, redrawId);
        });
      }
    };

    CanvasPainter.prototype._compositeManually = function () {
      var ctx = this.getLayer(CANVAS_ZLEVEL).ctx;
      var width = this._domRoot.width;
      var height = this._domRoot.height;
      ctx.clearRect(0, 0, width, height);
      this.eachBuiltinLayer(function (layer) {
        if (layer.virtual) {
          ctx.drawImage(layer.dom, 0, 0, width, height);
        }
      });
    };

    CanvasPainter.prototype._doPaintList = function (list, paintAll) {
      var layerList = [];

      for (var zi = 0; zi < this._zlevelList.length; zi++) {
        var zlevel = this._zlevelList[zi];
        var layer = this._layers[zlevel];

        if (layer.__builtin__ && layer !== this._hoverlayer && (layer.__dirty || paintAll)) {
          layerList.push(layer);
        }
      }

      var finished = true;
      var needsRefreshHover = false;

      for (var k = 0; k < layerList.length; k++) {
        var layer = layerList[k];
        var ctx = layer.ctx;
        var scope = {
          inHover: false,
          allClipped: false,
          prevEl: null,
          viewWidth: this._width,
          viewHeight: this._height
        };
        ctx.save();
        var start = paintAll ? layer.__startIndex : layer.__drawIndex;
        var useTimer = !paintAll && layer.incremental && Date.now;
        var startTime = useTimer && Date.now();
        var clearColor = layer.zlevel === this._zlevelList[0] ? this._backgroundColor : null;

        if (layer.__startIndex === layer.__endIndex) {
          layer.clear(false, clearColor);
        } else if (start === layer.__startIndex) {
          var firstEl = list[start];

          if (!firstEl.incremental || !firstEl.notClear || paintAll) {
            layer.clear(false, clearColor);
          }
        }

        if (start === -1) {
          console.error('For some unknown reason. drawIndex is -1');
          start = layer.__startIndex;
        }

        var i = void 0;

        for (i = start; i < layer.__endIndex; i++) {
          var el = list[i];

          if (el.__inHover) {
            needsRefreshHover = true;
          }

          brush(ctx, el, scope, i === layer.__endIndex - 1);

          if (useTimer) {
            var dTime = Date.now() - startTime;

            if (dTime > 15) {
              break;
            }
          }
        }

        layer.__drawIndex = i;

        if (layer.__drawIndex < layer.__endIndex) {
          finished = false;
        }

        if (scope.prevElClipPaths) {
          ctx.restore();
        }

        ctx.restore();
      }

      if (env.wxa) {
        each(this._layers, function (layer) {
          if (layer && layer.ctx && layer.ctx.draw) {
            layer.ctx.draw();
          }
        });
      }

      return {
        finished: finished,
        needsRefreshHover: needsRefreshHover
      };
    };

    CanvasPainter.prototype.getLayer = function (zlevel, virtual) {
      if (this._singleCanvas && !this._needsManuallyCompositing) {
        zlevel = CANVAS_ZLEVEL;
      }

      var layer = this._layers[zlevel];

      if (!layer) {
        layer = new Layer('zr_' + zlevel, this, this.dpr);
        layer.zlevel = zlevel;
        layer.__builtin__ = true;

        if (this._layerConfig[zlevel]) {
          merge(layer, this._layerConfig[zlevel], true);
        } else if (this._layerConfig[zlevel - EL_AFTER_INCREMENTAL_INC]) {
          merge(layer, this._layerConfig[zlevel - EL_AFTER_INCREMENTAL_INC], true);
        }

        if (virtual) {
          layer.virtual = virtual;
        }

        this.insertLayer(zlevel, layer);
        layer.initContext();
      }

      return layer;
    };

    CanvasPainter.prototype.insertLayer = function (zlevel, layer) {
      var layersMap = this._layers;
      var zlevelList = this._zlevelList;
      var len = zlevelList.length;
      var domRoot = this._domRoot;
      var prevLayer = null;
      var i = -1;

      if (layersMap[zlevel]) {
        logError('ZLevel ' + zlevel + ' has been used already');
        return;
      }

      if (!isLayerValid(layer)) {
        logError('Layer of zlevel ' + zlevel + ' is not valid');
        return;
      }

      if (len > 0 && zlevel > zlevelList[0]) {
        for (i = 0; i < len - 1; i++) {
          if (zlevelList[i] < zlevel && zlevelList[i + 1] > zlevel) {
            break;
          }
        }

        prevLayer = layersMap[zlevelList[i]];
      }

      zlevelList.splice(i + 1, 0, zlevel);
      layersMap[zlevel] = layer;

      if (!layer.virtual) {
        if (prevLayer) {
          var prevDom = prevLayer.dom;

          if (prevDom.nextSibling) {
            domRoot.insertBefore(layer.dom, prevDom.nextSibling);
          } else {
            domRoot.appendChild(layer.dom);
          }
        } else {
          if (domRoot.firstChild) {
            domRoot.insertBefore(layer.dom, domRoot.firstChild);
          } else {
            domRoot.appendChild(layer.dom);
          }
        }
      }

      layer.__painter = this;
    };

    CanvasPainter.prototype.eachLayer = function (cb, context) {
      var zlevelList = this._zlevelList;

      for (var i = 0; i < zlevelList.length; i++) {
        var z = zlevelList[i];
        cb.call(context, this._layers[z], z);
      }
    };

    CanvasPainter.prototype.eachBuiltinLayer = function (cb, context) {
      var zlevelList = this._zlevelList;

      for (var i = 0; i < zlevelList.length; i++) {
        var z = zlevelList[i];
        var layer = this._layers[z];

        if (layer.__builtin__) {
          cb.call(context, layer, z);
        }
      }
    };

    CanvasPainter.prototype.eachOtherLayer = function (cb, context) {
      var zlevelList = this._zlevelList;

      for (var i = 0; i < zlevelList.length; i++) {
        var z = zlevelList[i];
        var layer = this._layers[z];

        if (!layer.__builtin__) {
          cb.call(context, layer, z);
        }
      }
    };

    CanvasPainter.prototype.getLayers = function () {
      return this._layers;
    };

    CanvasPainter.prototype._updateLayerStatus = function (list) {
      this.eachBuiltinLayer(function (layer, z) {
        layer.__dirty = layer.__used = false;
      });

      function updatePrevLayer(idx) {
        if (prevLayer) {
          if (prevLayer.__endIndex !== idx) {
            prevLayer.__dirty = true;
          }

          prevLayer.__endIndex = idx;
        }
      }

      if (this._singleCanvas) {
        for (var i_1 = 1; i_1 < list.length; i_1++) {
          var el = list[i_1];

          if (el.zlevel !== list[i_1 - 1].zlevel || el.incremental) {
            this._needsManuallyCompositing = true;
            break;
          }
        }
      }

      var prevLayer = null;
      var incrementalLayerCount = 0;
      var prevZlevel;
      var i;

      for (i = 0; i < list.length; i++) {
        var el = list[i];
        var zlevel = el.zlevel;
        var layer = void 0;

        if (prevZlevel !== zlevel) {
          prevZlevel = zlevel;
          incrementalLayerCount = 0;
        }

        if (el.incremental) {
          layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing);
          layer.incremental = true;
          incrementalLayerCount = 1;
        } else {
          layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing);
        }

        if (!layer.__builtin__) {
          logError('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id);
        }

        if (layer !== prevLayer) {
          layer.__used = true;

          if (layer.__startIndex !== i) {
            layer.__dirty = true;
          }

          layer.__startIndex = i;

          if (!layer.incremental) {
            layer.__drawIndex = i;
          } else {
            layer.__drawIndex = -1;
          }

          updatePrevLayer(i);
          prevLayer = layer;
        }

        if (el.__dirty & Element.REDARAW_BIT && !el.__inHover) {
          layer.__dirty = true;

          if (layer.incremental && layer.__drawIndex < 0) {
            layer.__drawIndex = i;
          }
        }
      }

      updatePrevLayer(i);
      this.eachBuiltinLayer(function (layer, z) {
        if (!layer.__used && layer.getElementCount() > 0) {
          layer.__dirty = true;
          layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0;
        }

        if (layer.__dirty && layer.__drawIndex < 0) {
          layer.__drawIndex = layer.__startIndex;
        }
      });
    };

    CanvasPainter.prototype.clear = function () {
      this.eachBuiltinLayer(this._clearLayer);
      return this;
    };

    CanvasPainter.prototype._clearLayer = function (layer) {
      layer.clear();
    };

    CanvasPainter.prototype.setBackgroundColor = function (backgroundColor) {
      this._backgroundColor = backgroundColor;
    };

    CanvasPainter.prototype.configLayer = function (zlevel, config) {
      if (config) {
        var layerConfig = this._layerConfig;

        if (!layerConfig[zlevel]) {
          layerConfig[zlevel] = config;
        } else {
          merge(layerConfig[zlevel], config, true);
        }

        for (var i = 0; i < this._zlevelList.length; i++) {
          var _zlevel = this._zlevelList[i];

          if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) {
            var layer = this._layers[_zlevel];
            merge(layer, layerConfig[zlevel], true);
          }
        }
      }
    };

    CanvasPainter.prototype.delLayer = function (zlevel) {
      var layers = this._layers;
      var zlevelList = this._zlevelList;
      var layer = layers[zlevel];

      if (!layer) {
        return;
      }

      layer.dom.parentNode.removeChild(layer.dom);
      delete layers[zlevel];
      zlevelList.splice(indexOf(zlevelList, zlevel), 1);
    };

    CanvasPainter.prototype.resize = function (width, height) {
      if (!this._domRoot.style) {
        if (width == null || height == null) {
          return;
        }

        this._width = width;
        this._height = height;
        this.getLayer(CANVAS_ZLEVEL).resize(width, height);
      } else {
        var domRoot = this._domRoot;
        domRoot.style.display = 'none';
        var opts = this._opts;
        width != null && (opts.width = width);
        height != null && (opts.height = height);
        width = this._getSize(0);
        height = this._getSize(1);
        domRoot.style.display = '';

        if (this._width !== width || height !== this._height) {
          domRoot.style.width = width + 'px';
          domRoot.style.height = height + 'px';

          for (var id in this._layers) {
            if (this._layers.hasOwnProperty(id)) {
              this._layers[id].resize(width, height);
            }
          }

          this.refresh(true);
        }

        this._width = width;
        this._height = height;
      }

      return this;
    };

    CanvasPainter.prototype.clearLayer = function (zlevel) {
      var layer = this._layers[zlevel];

      if (layer) {
        layer.clear();
      }
    };

    CanvasPainter.prototype.dispose = function () {
      this.root.innerHTML = '';
      this.root = this.storage = this._domRoot = this._layers = null;
    };

    CanvasPainter.prototype.getRenderedCanvas = function (opts) {
      opts = opts || {};

      if (this._singleCanvas && !this._compositeManually) {
        return this._layers[CANVAS_ZLEVEL].dom;
      }

      var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);
      var ctx = imageLayer.ctx;
      imageLayer.initContext();
      imageLayer.clear(false, opts.backgroundColor || this._backgroundColor);

      if (opts.pixelRatio <= this.dpr) {
        this.refresh();
        var width_1 = imageLayer.dom.width;
        var height_1 = imageLayer.dom.height;
        var ctx_1 = imageLayer.ctx;
        this.eachLayer(function (layer) {
          if (layer.__builtin__) {
            ctx_1.drawImage(layer.dom, 0, 0, width_1, height_1);
          } else if (layer.renderToCanvas) {
            imageLayer.ctx.save();
            layer.renderToCanvas(imageLayer.ctx);
            imageLayer.ctx.restore();
          }
        });
      } else {
        var scope = {
          inHover: false,
          viewWidth: this._width,
          viewHeight: this._height
        };
        var displayList = this.storage.getDisplayList(true);

        for (var i = 0, len = displayList.length; i < len; i++) {
          var el = displayList[i];
          brush(ctx, el, scope, i === len - 1);
        }
      }

      return imageLayer.dom;
    };

    CanvasPainter.prototype.getWidth = function () {
      return this._width;
    };

    CanvasPainter.prototype.getHeight = function () {
      return this._height;
    };

    CanvasPainter.prototype._getSize = function (whIdx) {
      var opts = this._opts;
      var wh = ['width', 'height'][whIdx];
      var cwh = ['clientWidth', 'clientHeight'][whIdx];
      var plt = ['paddingLeft', 'paddingTop'][whIdx];
      var prb = ['paddingRight', 'paddingBottom'][whIdx];

      if (opts[wh] != null && opts[wh] !== 'auto') {
        return parseFloat(opts[wh]);
      }

      var root = this.root;
      var stl = document.defaultView.getComputedStyle(root);
      return (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh])) - (parseInt10(stl[plt]) || 0) - (parseInt10(stl[prb]) || 0) | 0;
    };

    CanvasPainter.prototype.pathToImage = function (path, dpr) {
      dpr = dpr || this.dpr;
      var canvas = document.createElement('canvas');
      var ctx = canvas.getContext('2d');
      var rect = path.getBoundingRect();
      var style = path.style;
      var shadowBlurSize = style.shadowBlur * dpr;
      var shadowOffsetX = style.shadowOffsetX * dpr;
      var shadowOffsetY = style.shadowOffsetY * dpr;
      var lineWidth = path.hasStroke() ? style.lineWidth : 0;
      var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize);
      var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize);
      var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize);
      var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize);
      var width = rect.width + leftMargin + rightMargin;
      var height = rect.height + topMargin + bottomMargin;
      canvas.width = width * dpr;
      canvas.height = height * dpr;
      ctx.scale(dpr, dpr);
      ctx.clearRect(0, 0, width, height);
      ctx.dpr = dpr;
      var pathTransform = {
        x: path.x,
        y: path.y,
        scaleX: path.scaleX,
        scaleY: path.scaleY,
        rotation: path.rotation,
        originX: path.originX,
        originY: path.originY
      };
      path.x = leftMargin - rect.x;
      path.y = topMargin - rect.y;
      path.rotation = 0;
      path.scaleX = 1;
      path.scaleY = 1;
      path.updateTransform();

      if (path) {
        brush(ctx, path, {
          inHover: false,
          viewWidth: this._width,
          viewHeight: this._height
        }, true);
      }

      var imgShape = new ZRImage({
        style: {
          x: 0,
          y: 0,
          image: canvas
        }
      });
      extend(path, pathTransform);
      return imgShape;
    };

    return CanvasPainter;
  }();

  registerPainter('canvas', CanvasPainter);
  var assert$1 = assert;
  var each$3 = each;
  var isFunction$1 = isFunction;
  var isObject$2 = isObject;
  var version = '5.0.0-alpha.2';
  var dependencies = {
    zrender: '5.0.0-alpha.2'
  };
  var TEST_FRAME_REMAIN_TIME = 1;
  var PRIORITY_PROCESSOR_SERIES_FILTER = 800;
  var PRIORITY_PROCESSOR_DATASTACK = 900;
  var PRIORITY_PROCESSOR_FILTER = 1000;
  var PRIORITY_PROCESSOR_DEFAULT = 2000;
  var PRIORITY_PROCESSOR_STATISTIC = 5000;
  var PRIORITY_VISUAL_LAYOUT = 1000;
  var PRIORITY_VISUAL_PROGRESSIVE_LAYOUT = 1100;
  var PRIORITY_VISUAL_GLOBAL = 2000;
  var PRIORITY_VISUAL_CHART = 3000;
  var PRIORITY_VISUAL_POST_CHART_LAYOUT = 3500;
  var PRIORITY_VISUAL_COMPONENT = 4000;
  var PRIORITY_VISUAL_CHART_DATA_CUSTOM = 4500;
  var PRIORITY_VISUAL_BRUSH = 5000;
  var PRIORITY = {
    PROCESSOR: {
      FILTER: PRIORITY_PROCESSOR_FILTER,
      SERIES_FILTER: PRIORITY_PROCESSOR_SERIES_FILTER,
      STATISTIC: PRIORITY_PROCESSOR_STATISTIC
    },
    VISUAL: {
      LAYOUT: PRIORITY_VISUAL_LAYOUT,
      PROGRESSIVE_LAYOUT: PRIORITY_VISUAL_PROGRESSIVE_LAYOUT,
      GLOBAL: PRIORITY_VISUAL_GLOBAL,
      CHART: PRIORITY_VISUAL_CHART,
      POST_CHART_LAYOUT: PRIORITY_VISUAL_POST_CHART_LAYOUT,
      COMPONENT: PRIORITY_VISUAL_COMPONENT,
      BRUSH: PRIORITY_VISUAL_BRUSH,
      CHART_ITEM: PRIORITY_VISUAL_CHART_DATA_CUSTOM
    }
  };
  var IN_MAIN_PROCESS_KEY = '__flagInMainProcess';
  var OPTION_UPDATED_KEY = '__optionUpdated';
  var STATUS_NEEDS_UPDATE_KEY = '__needsUpdateStatus';
  var ACTION_REG = /^[a-zA-Z0-9_]+$/;
  var CONNECT_STATUS_KEY = '__connectUpdateStatus';
  var CONNECT_STATUS_PENDING = 0;
  var CONNECT_STATUS_UPDATING = 1;
  var CONNECT_STATUS_UPDATED = 2;

  function createRegisterEventWithLowercaseECharts(method) {
    return function () {
      var args = [];

      for (var _i = 0; _i < arguments.length; _i++) {
        args[_i] = arguments[_i];
      }

      if (this.isDisposed()) {
        disposedWarning(this.id);
        return;
      }

      return toLowercaseNameAndCallEventful(this, method, args);
    };
  }

  function createRegisterEventWithLowercaseMessageCenter(method) {
    return function () {
      var args = [];

      for (var _i = 0; _i < arguments.length; _i++) {
        args[_i] = arguments[_i];
      }

      return toLowercaseNameAndCallEventful(this, method, args);
    };
  }

  function toLowercaseNameAndCallEventful(host, method, args) {
    args[0] = args[0] && args[0].toLowerCase();
    return Eventful.prototype[method].apply(host, args);
  }

  var MessageCenter = function (_super) {
    __extends(MessageCenter, _super);

    function MessageCenter() {
      return _super !== null && _super.apply(this, arguments) || this;
    }

    return MessageCenter;
  }(Eventful);

  var messageCenterProto = MessageCenter.prototype;
  messageCenterProto.on = createRegisterEventWithLowercaseMessageCenter('on');
  messageCenterProto.off = createRegisterEventWithLowercaseMessageCenter('off');
  var prepare;
  var prepareView;
  var updateDirectly;
  var updateMethods;
  var doConvertPixel;
  var updateStreamModes;
  var doDispatchAction;
  var flushPendingActions;
  var triggerUpdatedEvent;
  var bindRenderedEvent;
  var bindMouseEvent;
  var clearColorPalette;
  var render;
  var renderComponents;
  var renderSeries;
  var performPostUpdateFuncs;
  var createExtensionAPI;
  var enableConnect;
  var markStatusToUpdate;
  var applyChangedStates;

  var ECharts = function (_super) {
    __extends(ECharts, _super);

    function ECharts(dom, theme, opts) {
      var _this = _super.call(this, new ECEventProcessor()) || this;

      _this._chartsViews = [];
      _this._chartsMap = {};
      _this._componentsViews = [];
      _this._componentsMap = {};
      _this._pendingActions = [];
      opts = opts || {};

      if (typeof theme === 'string') {
        theme = themeStorage[theme];
      }

      _this._dom = dom;
      var defaultRenderer = 'canvas';

      if (true) {
        defaultRenderer = (typeof window === 'undefined' ? global : window).__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer;
      }

      var zr = _this._zr = init(dom, {
        renderer: opts.renderer || defaultRenderer,
        devicePixelRatio: opts.devicePixelRatio,
        width: opts.width,
        height: opts.height
      });
      _this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);
      theme = clone(theme);
      theme && backwardCompat(theme, true);
      _this._theme = theme;
      _this._locale = createLocaleObject(opts.locale || SYSTEM_LANG);
      _this._coordSysMgr = new CoordinateSystemManager();
      var api = _this._api = createExtensionAPI(_this);

      function prioritySortFunc(a, b) {
        return a.__prio - b.__prio;
      }

      sort(visualFuncs, prioritySortFunc);
      sort(dataProcessorFuncs, prioritySortFunc);
      _this._scheduler = new Scheduler(_this, api, dataProcessorFuncs, visualFuncs);
      _this._messageCenter = new MessageCenter();
      _this._labelManager = new LabelManager();

      _this._initEvents();

      _this.resize = bind(_this.resize, _this);
      zr.animation.on('frame', _this._onframe, _this);
      bindRenderedEvent(zr, _this);
      bindMouseEvent(zr, _this);
      setAsPrimitive(_this);
      return _this;
    }

    ECharts.prototype._onframe = function () {
      if (this._disposed) {
        return;
      }

      applyChangedStates(this);
      var scheduler = this._scheduler;

      if (this[OPTION_UPDATED_KEY]) {
        var silent = this[OPTION_UPDATED_KEY].silent;
        this[IN_MAIN_PROCESS_KEY] = true;
        prepare(this);
        updateMethods.update.call(this);
        this[IN_MAIN_PROCESS_KEY] = false;
        this[OPTION_UPDATED_KEY] = false;
        flushPendingActions.call(this, silent);
        triggerUpdatedEvent.call(this, silent);
      } else if (scheduler.unfinished) {
        var remainTime = TEST_FRAME_REMAIN_TIME;
        var ecModel = this._model;
        var api = this._api;
        scheduler.unfinished = false;

        do {
          var startTime = +new Date();
          scheduler.performSeriesTasks(ecModel);
          scheduler.performDataProcessorTasks(ecModel);
          updateStreamModes(this, ecModel);
          scheduler.performVisualTasks(ecModel);
          renderSeries(this, this._model, api, 'remain');
          remainTime -= +new Date() - startTime;
        } while (remainTime > 0 && scheduler.unfinished);

        if (!scheduler.unfinished) {
          this._zr.flush();
        }
      }
    };

    ECharts.prototype.getDom = function () {
      return this._dom;
    };

    ECharts.prototype.getId = function () {
      return this.id;
    };

    ECharts.prototype.getZr = function () {
      return this._zr;
    };

    ECharts.prototype.setOption = function (option, notMerge, lazyUpdate) {
      if (true) {
        assert$1(!this[IN_MAIN_PROCESS_KEY], '`setOption` should not be called during main process.');
      }

      if (this._disposed) {
        disposedWarning(this.id);
        return;
      }

      var silent;
      var replaceMerge;

      if (isObject$2(notMerge)) {
        lazyUpdate = notMerge.lazyUpdate;
        silent = notMerge.silent;
        replaceMerge = notMerge.replaceMerge;
        notMerge = notMerge.notMerge;
      }

      this[IN_MAIN_PROCESS_KEY] = true;

      if (!this._model || notMerge) {
        var optionManager = new OptionManager(this._api);
        var theme = this._theme;
        var ecModel = this._model = new GlobalModel();
        ecModel.scheduler = this._scheduler;
        ecModel.init(null, null, null, theme, this._locale, optionManager);
      }

      this._model.setOption(option, {
        replaceMerge: replaceMerge
      }, optionPreprocessorFuncs);

      if (lazyUpdate) {
        this[OPTION_UPDATED_KEY] = {
          silent: silent
        };
        this[IN_MAIN_PROCESS_KEY] = false;
      } else {
        prepare(this);
        updateMethods.update.call(this);

        this._zr.flush();

        this[OPTION_UPDATED_KEY] = false;
        this[IN_MAIN_PROCESS_KEY] = false;
        flushPendingActions.call(this, silent);
        triggerUpdatedEvent.call(this, silent);
      }
    };

    ECharts.prototype.setTheme = function () {
      console.error('ECharts#setTheme() is DEPRECATED in ECharts 3.0');
    };

    ECharts.prototype.getModel = function () {
      return this._model;
    };

    ECharts.prototype.getOption = function () {
      return this._model && this._model.getOption();
    };

    ECharts.prototype.getWidth = function () {
      return this._zr.getWidth();
    };

    ECharts.prototype.getHeight = function () {
      return this._zr.getHeight();
    };

    ECharts.prototype.getDevicePixelRatio = function () {
      return this._zr.painter.dpr || window.devicePixelRatio || 1;
    };

    ECharts.prototype.getRenderedCanvas = function (opts) {
      if (!env.canvasSupported) {
        return;
      }

      opts = extend({}, opts || {});
      opts.pixelRatio = opts.pixelRatio || 1;
      opts.backgroundColor = opts.backgroundColor || this._model.get('backgroundColor');
      var zr = this._zr;
      return zr.painter.getRenderedCanvas(opts);
    };

    ECharts.prototype.getSvgDataURL = function () {
      if (!env.svgSupported) {
        return;
      }

      var zr = this._zr;
      var list = zr.storage.getDisplayList();
      each(list, function (el) {
        el.stopAnimation(null, true);
      });
      return zr.painter.toDataURL();
    };

    ECharts.prototype.getDataURL = function (opts) {
      if (this._disposed) {
        disposedWarning(this.id);
        return;
      }

      opts = opts || {};
      var excludeComponents = opts.excludeComponents;
      var ecModel = this._model;
      var excludesComponentViews = [];
      var self = this;
      each$3(excludeComponents, function (componentType) {
        ecModel.eachComponent({
          mainType: componentType
        }, function (component) {
          var view = self._componentsMap[component.__viewId];

          if (!view.group.ignore) {
            excludesComponentViews.push(view);
            view.group.ignore = true;
          }
        });
      });
      var url = this._zr.painter.getType() === 'svg' ? this.getSvgDataURL() : this.getRenderedCanvas(opts).toDataURL('image/' + (opts && opts.type || 'png'));
      each$3(excludesComponentViews, function (view) {
        view.group.ignore = false;
      });
      return url;
    };

    ECharts.prototype.getConnectedDataURL = function (opts) {
      if (this._disposed) {
        disposedWarning(this.id);
        return;
      }

      if (!env.canvasSupported) {
        return;
      }

      var isSvg = opts.type === 'svg';
      var groupId = this.group;
      var mathMin = Math.min;
      var mathMax = Math.max;
      var MAX_NUMBER = Infinity;

      if (connectedGroups[groupId]) {
        var left_1 = MAX_NUMBER;
        var top_1 = MAX_NUMBER;
        var right_1 = -MAX_NUMBER;
        var bottom_1 = -MAX_NUMBER;
        var canvasList_1 = [];
        var dpr_1 = opts && opts.pixelRatio || 1;
        each(instances, function (chart, id) {
          if (chart.group === groupId) {
            var canvas = isSvg ? chart.getZr().painter.getSvgDom().innerHTML : chart.getRenderedCanvas(clone(opts));
            var boundingRect = chart.getDom().getBoundingClientRect();
            left_1 = mathMin(boundingRect.left, left_1);
            top_1 = mathMin(boundingRect.top, top_1);
            right_1 = mathMax(boundingRect.right, right_1);
            bottom_1 = mathMax(boundingRect.bottom, bottom_1);
            canvasList_1.push({
              dom: canvas,
              left: boundingRect.left,
              top: boundingRect.top
            });
          }
        });
        left_1 *= dpr_1;
        top_1 *= dpr_1;
        right_1 *= dpr_1;
        bottom_1 *= dpr_1;
        var width = right_1 - left_1;
        var height = bottom_1 - top_1;
        var targetCanvas = createCanvas();
        var zr_1 = init(targetCanvas, {
          renderer: isSvg ? 'svg' : 'canvas'
        });
        zr_1.resize({
          width: width,
          height: height
        });

        if (isSvg) {
          var content_1 = '';
          each$3(canvasList_1, function (item) {
            var x = item.left - left_1;
            var y = item.top - top_1;
            content_1 += '<g transform="translate(' + x + ',' + y + ')">' + item.dom + '</g>';
          });
          zr_1.painter.getSvgRoot().innerHTML = content_1;

          if (opts.connectedBackgroundColor) {
            zr_1.painter.setBackgroundColor(opts.connectedBackgroundColor);
          }

          zr_1.refreshImmediately();
          return zr_1.painter.toDataURL();
        } else {
          if (opts.connectedBackgroundColor) {
            zr_1.add(new Rect({
              shape: {
                x: 0,
                y: 0,
                width: width,
                height: height
              },
              style: {
                fill: opts.connectedBackgroundColor
              }
            }));
          }

          each$3(canvasList_1, function (item) {
            var img = new ZRImage({
              style: {
                x: item.left * dpr_1 - left_1,
                y: item.top * dpr_1 - top_1,
                image: item.dom
              }
            });
            zr_1.add(img);
          });
          zr_1.refreshImmediately();
          return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));
        }
      } else {
        return this.getDataURL(opts);
      }
    };

    ECharts.prototype.convertToPixel = function (finder, value) {
      return doConvertPixel(this, 'convertToPixel', finder, value);
    };

    ECharts.prototype.convertFromPixel = function (finder, value) {
      return doConvertPixel(this, 'convertFromPixel', finder, value);
    };

    ECharts.prototype.containPixel = function (finder, value) {
      if (this._disposed) {
        disposedWarning(this.id);
        return;
      }

      var ecModel = this._model;
      var result;
      var findResult = parseFinder(ecModel, finder);
      each(findResult, function (models, key) {
        key.indexOf('Models') >= 0 && each(models, function (model) {
          var coordSys = model.coordinateSystem;

          if (coordSys && coordSys.containPoint) {
            result = result || !!coordSys.containPoint(value);
          } else if (key === 'seriesModels') {
            var view = this._chartsMap[model.__viewId];

            if (view && view.containPoint) {
              result = result || view.containPoint(value, model);
            } else {
              if (true) {
                console.warn(key + ': ' + (view ? 'The found component do not support containPoint.' : 'No view mapping to the found component.'));
              }
            }
          } else {
            if (true) {
              console.warn(key + ': containPoint is not supported');
            }
          }
        }, this);
      }, this);
      return !!result;
    };

    ECharts.prototype.getVisual = function (finder, visualType) {
      var ecModel = this._model;
      var parsedFinder = parseFinder(ecModel, finder, {
        defaultMainType: 'series'
      });
      var seriesModel = parsedFinder.seriesModel;

      if (true) {
        if (!seriesModel) {
          console.warn('There is no specified seires model');
        }
      }

      var data = seriesModel.getData();
      var dataIndexInside = parsedFinder.hasOwnProperty('dataIndexInside') ? parsedFinder.dataIndexInside : parsedFinder.hasOwnProperty('dataIndex') ? data.indexOfRawIndex(parsedFinder.dataIndex) : null;
      return dataIndexInside != null ? getItemVisualFromData(data, dataIndexInside, visualType) : getVisualFromData(data, visualType);
    };

    ECharts.prototype.getViewOfComponentModel = function (componentModel) {
      return this._componentsMap[componentModel.__viewId];
    };

    ECharts.prototype.getViewOfSeriesModel = function (seriesModel) {
      return this._chartsMap[seriesModel.__viewId];
    };

    ECharts.prototype._initEvents = function () {
      var _this = this;

      each$3(MOUSE_EVENT_NAMES, function (eveName) {
        var handler = function (e) {
          var ecModel = _this.getModel();

          var el = e.target;
          var params;
          var isGlobalOut = eveName === 'globalout';
          var ecData = el && getECData(el);

          if (isGlobalOut) {
            params = {};
          } else if (ecData && ecData.dataIndex != null) {
            var dataModel = ecData.dataModel || ecModel.getSeriesByIndex(ecData.seriesIndex);
            params = dataModel && dataModel.getDataParams(ecData.dataIndex, ecData.dataType) || {};
          } else if (el && ecData.eventData) {
            params = extend({}, ecData.eventData);
          }

          if (params) {
            var componentType = params.componentType;
            var componentIndex = params.componentIndex;

            if (componentType === 'markLine' || componentType === 'markPoint' || componentType === 'markArea') {
              componentType = 'series';
              componentIndex = params.seriesIndex;
            }

            var model = componentType && componentIndex != null && ecModel.getComponent(componentType, componentIndex);
            var view = model && _this[model.mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId];

            if (true) {
              if (!isGlobalOut && !(model && view)) {
                console.warn('model or view can not be found by params');
              }
            }

            params.event = e;
            params.type = eveName;
            _this._$eventProcessor.eventInfo = {
              targetEl: el,
              packedEvent: params,
              model: model,
              view: view
            };

            _this.trigger(eveName, params);
          }
        };

        handler.zrEventfulCallAtLast = true;

        _this._zr.on(eveName, handler, _this);
      });
      each$3(eventActionMap, function (actionType, eventType) {
        _this._messageCenter.on(eventType, function (event) {
          this.trigger(eventType, event);
        }, _this);
      });
      each$3(['selectchanged'], function (eventType) {
        _this._messageCenter.on(eventType, function (event) {
          this.trigger(eventType, event);
        }, _this);
      });
      handleLegacySelectEvents(this._messageCenter, this);
    };

    ECharts.prototype.isDisposed = function () {
      return this._disposed;
    };

    ECharts.prototype.clear = function () {
      if (this._disposed) {
        disposedWarning(this.id);
        return;
      }

      this.setOption({
        series: []
      }, true);
    };

    ECharts.prototype.dispose = function () {
      if (this._disposed) {
        disposedWarning(this.id);
        return;
      }

      this._disposed = true;
      setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');
      var api = this._api;
      var ecModel = this._model;
      each$3(this._componentsViews, function (component) {
        component.dispose(ecModel, api);
      });
      each$3(this._chartsViews, function (chart) {
        chart.dispose(ecModel, api);
      });

      this._zr.dispose();

      delete instances[this.id];
    };

    ECharts.prototype.resize = function (opts) {
      if (true) {
        assert$1(!this[IN_MAIN_PROCESS_KEY], '`resize` should not be called during main process.');
      }

      if (this._disposed) {
        disposedWarning(this.id);
        return;
      }

      this._zr.resize(opts);

      var ecModel = this._model;
      this._loadingFX && this._loadingFX.resize();

      if (!ecModel) {
        return;
      }

      var optionChanged = ecModel.resetOption('media');
      var silent = opts && opts.silent;
      this[IN_MAIN_PROCESS_KEY] = true;
      optionChanged && prepare(this);
      updateMethods.update.call(this, {
        type: 'resize',
        animation: {
          duration: 0
        }
      });
      this[IN_MAIN_PROCESS_KEY] = false;
      flushPendingActions.call(this, silent);
      triggerUpdatedEvent.call(this, silent);
    };

    ECharts.prototype.showLoading = function (name, cfg) {
      if (this._disposed) {
        disposedWarning(this.id);
        return;
      }

      if (isObject$2(name)) {
        cfg = name;
        name = '';
      }

      name = name || 'default';
      this.hideLoading();

      if (!loadingEffects[name]) {
        if (true) {
          console.warn('Loading effects ' + name + ' not exists.');
        }

        return;
      }

      var el = loadingEffects[name](this._api, cfg);
      var zr = this._zr;
      this._loadingFX = el;
      zr.add(el);
    };

    ECharts.prototype.hideLoading = function () {
      if (this._disposed) {
        disposedWarning(this.id);
        return;
      }

      this._loadingFX && this._zr.remove(this._loadingFX);
      this._loadingFX = null;
    };

    ECharts.prototype.makeActionFromEvent = function (eventObj) {
      var payload = extend({}, eventObj);
      payload.type = eventActionMap[eventObj.type];
      return payload;
    };

    ECharts.prototype.dispatchAction = function (payload, opt) {
      if (this._disposed) {
        disposedWarning(this.id);
        return;
      }

      if (!isObject$2(opt)) {
        opt = {
          silent: !!opt
        };
      }

      if (!actions[payload.type]) {
        return;
      }

      if (!this._model) {
        return;
      }

      if (this[IN_MAIN_PROCESS_KEY]) {
        this._pendingActions.push(payload);

        return;
      }

      var silent = opt.silent;
      doDispatchAction.call(this, payload, silent);
      var flush = opt.flush;

      if (flush) {
        this._zr.flush();
      } else if (flush !== false && env.browser.weChat) {
        this._throttledZrFlush();
      }

      flushPendingActions.call(this, silent);
      triggerUpdatedEvent.call(this, silent);
    };

    ECharts.prototype.updateLabelLayout = function () {
      var labelManager = this._labelManager;
      labelManager.updateLayoutConfig(this._api);
      labelManager.layout(this._api);
      labelManager.processLabelsOverall();
    };

    ECharts.prototype.appendData = function (params) {
      if (this._disposed) {
        disposedWarning(this.id);
        return;
      }

      var seriesIndex = params.seriesIndex;
      var ecModel = this.getModel();
      var seriesModel = ecModel.getSeriesByIndex(seriesIndex);

      if (true) {
        assert$1(params.data && seriesModel);
      }

      seriesModel.appendData(params);
      this._scheduler.unfinished = true;
      this.getZr().wakeUp();
    };

    ECharts.internalField = function () {
      prepare = function (ecIns) {
        var scheduler = ecIns._scheduler;
        scheduler.restorePipelines(ecIns._model);
        scheduler.prepareStageTasks();
        prepareView(ecIns, true);
        prepareView(ecIns, false);
        scheduler.plan();
      };

      prepareView = function (ecIns, isComponent) {
        var ecModel = ecIns._model;
        var scheduler = ecIns._scheduler;
        var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews;
        var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap;
        var zr = ecIns._zr;
        var api = ecIns._api;

        for (var i = 0; i < viewList.length; i++) {
          viewList[i].__alive = false;
        }

        isComponent ? ecModel.eachComponent(function (componentType, model) {
          componentType !== 'series' && doPrepare(model);
        }) : ecModel.eachSeries(doPrepare);

        function doPrepare(model) {
          var requireNewView = model.__requireNewView;
          model.__requireNewView = false;
          var viewId = '_ec_' + model.id + '_' + model.type;
          var view = !requireNewView && viewMap[viewId];

          if (!view) {
            var classType = parseClassType(model.type);
            var Clazz = isComponent ? ComponentView.getClass(classType.main, classType.sub) : ChartView.getClass(classType.sub);

            if (true) {
              assert$1(Clazz, classType.sub + ' does not exist.');
            }

            view = new Clazz();
            view.init(ecModel, api);
            viewMap[viewId] = view;
            viewList.push(view);
            zr.add(view.group);
          }

          model.__viewId = view.__id = viewId;
          view.__alive = true;
          view.__model = model;
          view.group.__ecComponentInfo = {
            mainType: model.mainType,
            index: model.componentIndex
          };
          !isComponent && scheduler.prepareView(view, model, ecModel, api);
        }

        for (var i = 0; i < viewList.length;) {
          var view = viewList[i];

          if (!view.__alive) {
            !isComponent && view.renderTask.dispose();
            zr.remove(view.group);
            view.dispose(ecModel, api);
            viewList.splice(i, 1);

            if (viewMap[view.__id] === view) {
              delete viewMap[view.__id];
            }

            view.__id = view.group.__ecComponentInfo = null;
          } else {
            i++;
          }
        }
      };

      updateDirectly = function (ecIns, method, payload, mainType, subType) {
        var ecModel = ecIns._model;
        ecModel.setUpdatePayload(payload);

        if (!mainType) {
          each$3([].concat(ecIns._componentsViews).concat(ecIns._chartsViews), callView);
          return;
        }

        var query = {};
        query[mainType + 'Id'] = payload[mainType + 'Id'];
        query[mainType + 'Index'] = payload[mainType + 'Index'];
        query[mainType + 'Name'] = payload[mainType + 'Name'];
        var condition = {
          mainType: mainType,
          query: query
        };
        subType && (condition.subType = subType);
        var excludeSeriesId = payload.excludeSeriesId;
        var excludeSeriesIdMap;

        if (excludeSeriesId != null) {
          excludeSeriesIdMap = createHashMap(normalizeToArray(excludeSeriesId));
        }

        ecModel && ecModel.eachComponent(condition, function (model) {
          if (!excludeSeriesIdMap || excludeSeriesIdMap.get(model.id) == null) {
            if (isHighDownPayload(payload) && !payload.notBlur) {
              if (model instanceof SeriesModel) {
                toggleSeriesBlurStateFromPayload(model, payload, ecIns);
              }
            } else if (isSelectChangePayload(payload)) {
              if (model instanceof SeriesModel) {
                toggleSelectionFromPayload(model, payload);
                updateSeriesElementSelection(model);
                markStatusToUpdate(ecIns);
              }
            }

            callView(ecIns[mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId]);
          }
        }, ecIns);

        function callView(view) {
          view && view.__alive && view[method] && view[method](view.__model, ecModel, ecIns._api, payload);
        }
      };

      updateMethods = {
        prepareAndUpdate: function (payload) {
          prepare(this);
          updateMethods.update.call(this, payload);
        },
        update: function (payload) {
          var ecModel = this._model;
          var api = this._api;
          var zr = this._zr;
          var coordSysMgr = this._coordSysMgr;
          var scheduler = this._scheduler;

          if (!ecModel) {
            return;
          }

          ecModel.setUpdatePayload(payload);
          scheduler.restoreData(ecModel, payload);
          scheduler.performSeriesTasks(ecModel);
          coordSysMgr.create(ecModel, api);
          scheduler.performDataProcessorTasks(ecModel, payload);
          updateStreamModes(this, ecModel);
          coordSysMgr.update(ecModel, api);
          clearColorPalette(ecModel);
          scheduler.performVisualTasks(ecModel, payload);
          render(this, ecModel, api, payload);
          var backgroundColor = ecModel.get('backgroundColor') || 'transparent';
          var darkMode = ecModel.get('darkMode');

          if (!env.canvasSupported) {
            var colorArr = parse(backgroundColor);
            backgroundColor = stringify(colorArr, 'rgb');

            if (colorArr[3] === 0) {
              backgroundColor = 'transparent';
            }
          } else {
            zr.setBackgroundColor(backgroundColor);

            if (darkMode != null && darkMode !== 'auto') {
              zr.setDarkMode(darkMode);
            }
          }

          performPostUpdateFuncs(ecModel, api);
        },
        updateTransform: function (payload) {
          var _this = this;

          var ecModel = this._model;
          var api = this._api;

          if (!ecModel) {
            return;
          }

          ecModel.setUpdatePayload(payload);
          var componentDirtyList = [];
          ecModel.eachComponent(function (componentType, componentModel) {
            if (componentType === 'series') {
              return;
            }

            var componentView = _this.getViewOfComponentModel(componentModel);

            if (componentView && componentView.__alive) {
              if (componentView.updateTransform) {
                var result = componentView.updateTransform(componentModel, ecModel, api, payload);
                result && result.update && componentDirtyList.push(componentView);
              } else {
                componentDirtyList.push(componentView);
              }
            }
          });
          var seriesDirtyMap = createHashMap();
          ecModel.eachSeries(function (seriesModel) {
            var chartView = _this._chartsMap[seriesModel.__viewId];

            if (chartView.updateTransform) {
              var result = chartView.updateTransform(seriesModel, ecModel, api, payload);
              result && result.update && seriesDirtyMap.set(seriesModel.uid, 1);
            } else {
              seriesDirtyMap.set(seriesModel.uid, 1);
            }
          });
          clearColorPalette(ecModel);

          this._scheduler.performVisualTasks(ecModel, payload, {
            setDirty: true,
            dirtyMap: seriesDirtyMap
          });

          renderSeries(this, ecModel, api, payload, seriesDirtyMap);
          performPostUpdateFuncs(ecModel, this._api);
        },
        updateView: function (payload) {
          var ecModel = this._model;

          if (!ecModel) {
            return;
          }

          ecModel.setUpdatePayload(payload);
          ChartView.markUpdateMethod(payload, 'updateView');
          clearColorPalette(ecModel);

          this._scheduler.performVisualTasks(ecModel, payload, {
            setDirty: true
          });

          render(this, this._model, this._api, payload);
          performPostUpdateFuncs(ecModel, this._api);
        },
        updateVisual: function (payload) {
          var _this = this;

          var ecModel = this._model;

          if (!ecModel) {
            return;
          }

          ecModel.setUpdatePayload(payload);
          ecModel.eachSeries(function (seriesModel) {
            seriesModel.getData().clearAllVisual();
          });
          ChartView.markUpdateMethod(payload, 'updateVisual');
          clearColorPalette(ecModel);

          this._scheduler.performVisualTasks(ecModel, payload, {
            visualType: 'visual',
            setDirty: true
          });

          ecModel.eachComponent(function (componentType, componentModel) {
            if (componentType !== 'series') {
              var componentView = _this.getViewOfComponentModel(componentModel);

              componentView && componentView.__alive && componentView.updateVisual(componentModel, ecModel, _this._api, payload);
            }
          });
          ecModel.eachSeries(function (seriesModel) {
            var chartView = _this._chartsMap[seriesModel.__viewId];
            chartView.updateVisual(seriesModel, ecModel, _this._api, payload);
          });
          performPostUpdateFuncs(ecModel, this._api);
        },
        updateLayout: function (payload) {
          updateMethods.update.call(this, payload);
        }
      };

      doConvertPixel = function (ecIns, methodName, finder, value) {
        if (ecIns._disposed) {
          disposedWarning(ecIns.id);
          return;
        }

        var ecModel = ecIns._model;

        var coordSysList = ecIns._coordSysMgr.getCoordinateSystems();

        var result;
        var parsedFinder = parseFinder(ecModel, finder);

        for (var i = 0; i < coordSysList.length; i++) {
          var coordSys = coordSysList[i];

          if (coordSys[methodName] && (result = coordSys[methodName](ecModel, parsedFinder, value)) != null) {
            return result;
          }
        }

        if (true) {
          console.warn('No coordinate system that supports ' + methodName + ' found by the given finder.');
        }
      };

      updateStreamModes = function (ecIns, ecModel) {
        var chartsMap = ecIns._chartsMap;
        var scheduler = ecIns._scheduler;
        ecModel.eachSeries(function (seriesModel) {
          scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]);
        });
      };

      doDispatchAction = function (payload, silent) {
        var _this = this;

        var ecModel = this.getModel();
        var payloadType = payload.type;
        var escapeConnect = payload.escapeConnect;
        var actionWrap = actions[payloadType];
        var actionInfo = actionWrap.actionInfo;
        var cptTypeTmp = (actionInfo.update || 'update').split(':');
        var updateMethod = cptTypeTmp.pop();
        var cptType = cptTypeTmp[0] != null && parseClassType(cptTypeTmp[0]);
        this[IN_MAIN_PROCESS_KEY] = true;
        var payloads = [payload];
        var batched = false;

        if (payload.batch) {
          batched = true;
          payloads = map(payload.batch, function (item) {
            item = defaults(extend({}, item), payload);
            item.batch = null;
            return item;
          });
        }

        var eventObjBatch = [];
        var eventObj;
        var isSelectChange = isSelectChangePayload(payload);
        var isStatusChange = isHighDownPayload(payload) || isSelectChange;
        each$3(payloads, function (batchItem) {
          eventObj = actionWrap.action(batchItem, _this._model, _this._api);
          eventObj = eventObj || extend({}, batchItem);
          eventObj.type = actionInfo.event || eventObj.type;
          eventObjBatch.push(eventObj);

          if (isStatusChange) {
            updateDirectly(_this, updateMethod, batchItem, 'series');
            markStatusToUpdate(_this);
          } else if (cptType) {
            updateDirectly(_this, updateMethod, batchItem, cptType.main, cptType.sub);
          }
        });

        if (payload.statusChanged) {
          markStatusToUpdate(this);
        }

        if (updateMethod !== 'none' && !isStatusChange && !cptType) {
          if (this[OPTION_UPDATED_KEY]) {
            prepare(this);
            updateMethods.update.call(this, payload);
            this[OPTION_UPDATED_KEY] = false;
          } else {
            updateMethods[updateMethod].call(this, payload);
          }
        }

        if (batched) {
          eventObj = {
            type: actionInfo.event || payloadType,
            escapeConnect: escapeConnect,
            batch: eventObjBatch
          };
        } else {
          eventObj = eventObjBatch[0];
        }

        this[IN_MAIN_PROCESS_KEY] = false;

        if (!silent) {
          var messageCenter = this._messageCenter;
          messageCenter.trigger(eventObj.type, eventObj);

          if (isSelectChange) {
            var newObj = {
              type: 'selectchanged',
              escapeConnect: escapeConnect,
              selected: getAllSelectedIndices(ecModel),
              isFromClick: payload.isFromClick || false,
              fromAction: payload.type,
              fromActionPayload: payload
            };
            messageCenter.trigger(newObj.type, newObj);
          }
        }
      };

      flushPendingActions = function (silent) {
        var pendingActions = this._pendingActions;

        while (pendingActions.length) {
          var payload = pendingActions.shift();
          doDispatchAction.call(this, payload, silent);
        }
      };

      triggerUpdatedEvent = function (silent) {
        !silent && this.trigger('updated');
      };

      bindRenderedEvent = function (zr, ecIns) {
        zr.on('rendered', function (params) {
          ecIns.trigger('rendered', params);

          if (zr.animation.isFinished() && !ecIns[OPTION_UPDATED_KEY] && !ecIns._scheduler.unfinished && !ecIns._pendingActions.length) {
            ecIns.trigger('finished');
          }
        });
      };

      bindMouseEvent = function (zr, ecIns) {
        function getDispatcher(target, det) {
          while (target && !det(target)) {
            if (target.__hostTarget) {
              target = target.__hostTarget;
            } else {
              target = target.parent;
            }
          }

          return target;
        }

        zr.on('mouseover', function (e) {
          var el = e.target;
          var dispatcher = getDispatcher(el, isHighDownDispatcher);

          if (dispatcher) {
            var ecData = getECData(dispatcher);
            toggleSeriesBlurState(ecData.seriesIndex, ecData.focus, ecData.blurScope, ecIns, true);
            enterEmphasisWhenMouseOver(dispatcher, e);
            markStatusToUpdate(ecIns);
          }
        }).on('mouseout', function (e) {
          var el = e.target;
          var dispatcher = getDispatcher(el, isHighDownDispatcher);

          if (dispatcher) {
            var ecData = getECData(dispatcher);
            toggleSeriesBlurState(ecData.seriesIndex, ecData.focus, ecData.blurScope, ecIns, false);
            leaveEmphasisWhenMouseOut(dispatcher, e);
            markStatusToUpdate(ecIns);
          }
        }).on('click', function (e) {
          var el = e.target;
          var dispatcher = getDispatcher(el, function (target) {
            return getECData(target).dataIndex != null;
          });

          if (dispatcher) {
            var actionType = dispatcher.selected ? 'unselect' : 'select';
            var ecData = getECData(dispatcher);

            ecIns._api.dispatchAction({
              type: actionType,
              dataType: ecData.dataType,
              dataIndexInside: ecData.dataIndex,
              seriesIndex: ecData.seriesIndex,
              isFromClick: true
            });
          }
        });
      };

      clearColorPalette = function (ecModel) {
        ecModel.clearColorPalette();
        ecModel.eachSeries(function (seriesModel) {
          seriesModel.clearColorPalette();
        });
      };

      render = function (ecIns, ecModel, api, payload) {
        renderComponents(ecIns, ecModel, api, payload);
        each$3(ecIns._chartsViews, function (chart) {
          chart.__alive = false;
        });
        renderSeries(ecIns, ecModel, api, payload);
        each$3(ecIns._chartsViews, function (chart) {
          if (!chart.__alive) {
            chart.remove(ecModel, api);
          }
        });
      };

      renderComponents = function (ecIns, ecModel, api, payload, dirtyList) {
        each$3(dirtyList || ecIns._componentsViews, function (componentView) {
          var componentModel = componentView.__model;
          clearStates(componentModel, componentView);
          componentView.render(componentModel, ecModel, api, payload);
          updateZ(componentModel, componentView);
          updateStates(componentModel, componentView);
        });
      };

      renderSeries = function (ecIns, ecModel, api, payload, dirtyMap) {
        var scheduler = ecIns._scheduler;
        var labelManager = ecIns._labelManager;
        labelManager.clearLabels();
        var unfinished = false;
        ecModel.eachSeries(function (seriesModel) {
          var chartView = ecIns._chartsMap[seriesModel.__viewId];
          chartView.__alive = true;
          var renderTask = chartView.renderTask;
          scheduler.updatePayload(renderTask, payload);
          clearStates(seriesModel, chartView);

          if (dirtyMap && dirtyMap.get(seriesModel.uid)) {
            renderTask.dirty();
          }

          if (renderTask.perform(scheduler.getPerformArgs(renderTask))) {
            unfinished = true;
          }

          chartView.group.silent = !!seriesModel.get('silent');
          updateZ(seriesModel, chartView);
          updateBlend(seriesModel, chartView);
          updateSeriesElementSelection(seriesModel);
          labelManager.addLabelsOfSeries(chartView);
        });
        scheduler.unfinished = unfinished || scheduler.unfinished;
        labelManager.updateLayoutConfig(api);
        labelManager.layout(api);
        labelManager.processLabelsOverall();
        ecModel.eachSeries(function (seriesModel) {
          var chartView = ecIns._chartsMap[seriesModel.__viewId];
          updateStates(seriesModel, chartView);
        });
        updateHoverLayerStatus(ecIns, ecModel);
        aria(ecIns._zr.dom, ecModel);
      };

      performPostUpdateFuncs = function (ecModel, api) {
        each$3(postUpdateFuncs, function (func) {
          func(ecModel, api);
        });
      };

      markStatusToUpdate = function (ecIns) {
        ecIns[STATUS_NEEDS_UPDATE_KEY] = true;
        ecIns.getZr().wakeUp();
      };

      applyChangedStates = function (ecIns) {
        if (!ecIns[STATUS_NEEDS_UPDATE_KEY]) {
          return;
        }

        ecIns.getZr().storage.traverse(function (el) {
          if (isElementRemoved(el)) {
            return;
          }

          applyElementStates(el);
        });
        ecIns[STATUS_NEEDS_UPDATE_KEY] = false;
      };

      function applyElementStates(el) {
        var newStates = [];
        var oldStates = el.currentStates;

        for (var i = 0; i < oldStates.length; i++) {
          var stateName = oldStates[i];

          if (!(stateName === 'emphasis' || stateName === 'blur' || stateName === 'select')) {
            newStates.push(stateName);
          }
        }

        if (el.selected && el.states.select) {
          newStates.push('select');
        }

        if (el.hoverState === HOVER_STATE_EMPHASIS && el.states.emphasis) {
          newStates.push('emphasis');
        } else if (el.hoverState === HOVER_STATE_BLUR && el.states.blur) {
          newStates.push('blur');
        }

        el.useStates(newStates);
      }

      function updateHoverLayerStatus(ecIns, ecModel) {
        var zr = ecIns._zr;
        var storage = zr.storage;
        var elCount = 0;
        storage.traverse(function (el) {
          if (!el.isGroup) {
            elCount++;
          }
        });

        if (elCount > ecModel.get('hoverLayerThreshold') && !env.node) {
          ecModel.eachSeries(function (seriesModel) {
            if (seriesModel.preventUsingHoverLayer) {
              return;
            }

            var chartView = ecIns._chartsMap[seriesModel.__viewId];

            if (chartView.__alive) {
              chartView.group.traverse(function (el) {
                if (el.states.emphasis) {
                  el.states.emphasis.hoverLayer = true;
                }
              });
            }
          });
        }
      }

      function updateBlend(seriesModel, chartView) {
        var blendMode = seriesModel.get('blendMode') || null;

        if (true) {
          if (!env.canvasSupported && blendMode && blendMode !== 'source-over') {
            console.warn('Only canvas support blendMode');
          }
        }

        chartView.group.traverse(function (el) {
          if (!el.isGroup) {
            el.style.blend = blendMode;
          }

          if (el.eachPendingDisplayable) {
            el.eachPendingDisplayable(function (displayable) {
              displayable.style.blend = blendMode;
            });
          }
        });
      }

      function updateZ(model, view) {
        if (model.preventAutoZ) {
          return;
        }

        var z = model.get('z');
        var zlevel = model.get('zlevel');
        view.group.traverse(function (el) {
          if (!el.isGroup) {
            z != null && (el.z = z);
            zlevel != null && (el.zlevel = zlevel);
            var label = el.getTextContent();
            var labelLine = el.getTextGuideLine();

            if (label) {
              label.z = el.z;
              label.zlevel = el.zlevel;
              label.z2 = el.z2 + 1;
            }

            if (labelLine) {
              labelLine.z = el.z;
              labelLine.zlevel = el.zlevel;
              labelLine.z2 = el.z2 - 1;
            }
          }
        });
      }

      function clearStates(model, view) {
        view.group.traverse(function (el) {
          if (isElementRemoved(el)) {
            return;
          }

          var textContent = el.getTextContent();
          var textGuide = el.getTextGuideLine();

          if (el.stateTransition) {
            el.stateTransition = null;
          }

          if (textContent && textContent.stateTransition) {
            textContent.stateTransition = null;
          }

          if (textGuide && textGuide.stateTransition) {
            textGuide.stateTransition = null;
          }

          if (el.hasState()) {
            el.prevStates = el.currentStates;
            el.clearStates();
          } else if (el.prevStates) {
            el.prevStates = null;
          }
        });
      }

      function updateStates(model, view) {
        var stateAnimationModel = model.getModel('stateAnimation');
        var enableAnimation = model.isAnimationEnabled();
        var duration = stateAnimationModel.get('duration');
        var stateTransition = duration > 0 ? {
          duration: duration,
          delay: stateAnimationModel.get('delay'),
          easing: stateAnimationModel.get('easing')
        } : null;
        view.group.traverse(function (el) {
          if (el.states && el.states.emphasis) {
            if (isElementRemoved(el)) {
              return;
            }

            if (el instanceof Path) {
              savePathStates(el);
            }

            if (el.__dirty) {
              var prevStates = el.prevStates;

              if (prevStates) {
                el.useStates(prevStates);
              }
            }

            if (enableAnimation) {
              el.stateTransition = stateTransition;
              var textContent = el.getTextContent();
              var textGuide = el.getTextGuideLine();

              if (textContent) {
                textContent.stateTransition = stateTransition;
              }

              if (textGuide) {
                textGuide.stateTransition = stateTransition;
              }
            }

            if (el.__dirty) {
              applyElementStates(el);
            }
          }
        });
      }

      createExtensionAPI = function (ecIns) {
        return new (function (_super) {
          __extends(class_1, _super);

          function class_1() {
            return _super !== null && _super.apply(this, arguments) || this;
          }

          class_1.prototype.getCoordinateSystems = function () {
            return ecIns._coordSysMgr.getCoordinateSystems();
          };

          class_1.prototype.getComponentByElement = function (el) {
            while (el) {
              var modelInfo = el.__ecComponentInfo;

              if (modelInfo != null) {
                return ecIns._model.getComponent(modelInfo.mainType, modelInfo.index);
              }

              el = el.parent;
            }
          };

          class_1.prototype.enterEmphasis = function (el, highlightDigit) {
            enterEmphasis(el, highlightDigit);
            markStatusToUpdate(ecIns);
          };

          class_1.prototype.leaveEmphasis = function (el, highlightDigit) {
            leaveEmphasis(el, highlightDigit);
            markStatusToUpdate(ecIns);
          };

          class_1.prototype.enterBlur = function (el) {
            enterBlur(el);
            markStatusToUpdate(ecIns);
          };

          class_1.prototype.leaveBlur = function (el) {
            leaveBlur(el);
            markStatusToUpdate(ecIns);
          };

          class_1.prototype.enterSelect = function (el) {
            enterSelect(el);
            markStatusToUpdate(ecIns);
          };

          class_1.prototype.leaveSelect = function (el) {
            leaveSelect(el);
            markStatusToUpdate(ecIns);
          };

          return class_1;
        }(ExtensionAPI))(ecIns);
      };

      enableConnect = function (chart) {
        function updateConnectedChartsStatus(charts, status) {
          for (var i = 0; i < charts.length; i++) {
            var otherChart = charts[i];
            otherChart[CONNECT_STATUS_KEY] = status;
          }
        }

        each$3(eventActionMap, function (actionType, eventType) {
          chart._messageCenter.on(eventType, function (event) {
            if (connectedGroups[chart.group] && chart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_PENDING) {
              if (event && event.escapeConnect) {
                return;
              }

              var action_1 = chart.makeActionFromEvent(event);
              var otherCharts_1 = [];
              each$3(instances, function (otherChart) {
                if (otherChart !== chart && otherChart.group === chart.group) {
                  otherCharts_1.push(otherChart);
                }
              });
              updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_PENDING);
              each$3(otherCharts_1, function (otherChart) {
                if (otherChart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_UPDATING) {
                  otherChart.dispatchAction(action_1);
                }
              });
              updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_UPDATED);
            }
          });
        });
      };
    }();

    return ECharts;
  }(Eventful);

  var echartsProto = ECharts.prototype;
  echartsProto.on = createRegisterEventWithLowercaseECharts('on');
  echartsProto.off = createRegisterEventWithLowercaseECharts('off');

  echartsProto.one = function (eventName, cb, ctx) {
    var self = this;
    deprecateLog('ECharts#one is deprecated.');

    function wrapped() {
      var args2 = [];

      for (var _i = 0; _i < arguments.length; _i++) {
        args2[_i] = arguments[_i];
      }

      cb && cb.apply && cb.apply(this, args2);
      self.off(eventName, wrapped);
    }

    this.on.call(this, eventName, wrapped, ctx);
  };

  var MOUSE_EVENT_NAMES = ['click', 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'mouseup', 'globalout', 'contextmenu'];

  function disposedWarning(id) {
    if (true) {
      console.warn('Instance ' + id + ' has been disposed');
    }
  }

  var actions = {};
  var eventActionMap = {};
  var dataProcessorFuncs = [];
  var optionPreprocessorFuncs = [];
  var postUpdateFuncs = [];
  var visualFuncs = [];
  var themeStorage = {};
  var loadingEffects = {};
  var instances = {};
  var connectedGroups = {};
  var idBase = +new Date() - 0;
  var groupIdBase = +new Date() - 0;
  var DOM_ATTRIBUTE_KEY = '_echarts_instance_';

  function init$1(dom, theme, opts) {
    if (true) {
      if (!dom) {
        throw new Error('Initialize failed: invalid dom.');
      }
    }

    var existInstance = getInstanceByDom(dom);

    if (existInstance) {
      if (true) {
        console.warn('There is a chart instance already initialized on the dom.');
      }

      return existInstance;
    }

    if (true) {
      if (isDom(dom) && dom.nodeName.toUpperCase() !== 'CANVAS' && (!dom.clientWidth && (!opts || opts.width == null) || !dom.clientHeight && (!opts || opts.height == null))) {
        console.warn('Can\'t get DOM width or height. Please check ' + 'dom.clientWidth and dom.clientHeight. They should not be 0.' + 'For example, you may need to call this in the callback ' + 'of window.onload.');
      }
    }

    var chart = new ECharts(dom, theme, opts);
    chart.id = 'ec_' + idBase++;
    instances[chart.id] = chart;
    setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);
    enableConnect(chart);
    return chart;
  }

  function connect(groupId) {
    if (isArray(groupId)) {
      var charts = groupId;
      groupId = null;
      each$3(charts, function (chart) {
        if (chart.group != null) {
          groupId = chart.group;
        }
      });
      groupId = groupId || 'g_' + groupIdBase++;
      each$3(charts, function (chart) {
        chart.group = groupId;
      });
    }

    connectedGroups[groupId] = true;
    return groupId;
  }

  function disConnect(groupId) {
    connectedGroups[groupId] = false;
  }

  var disconnect = disConnect;

  function dispose(chart) {
    if (typeof chart === 'string') {
      chart = instances[chart];
    } else if (!(chart instanceof ECharts)) {
      chart = getInstanceByDom(chart);
    }

    if (chart instanceof ECharts && !chart.isDisposed()) {
      chart.dispose();
    }
  }

  function getInstanceByDom(dom) {
    return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)];
  }

  function getInstanceById(key) {
    return instances[key];
  }

  function registerTheme(name, theme) {
    themeStorage[name] = theme;
  }

  function registerPreprocessor(preprocessorFunc) {
    optionPreprocessorFuncs.push(preprocessorFunc);
  }

  function registerProcessor(priority, processor) {
    normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_DEFAULT);
  }

  function registerPostUpdate(postUpdateFunc) {
    postUpdateFuncs.push(postUpdateFunc);
  }

  function registerAction(actionInfo, eventName, action) {
    if (typeof eventName === 'function') {
      action = eventName;
      eventName = '';
    }

    var actionType = isObject$2(actionInfo) ? actionInfo.type : [actionInfo, actionInfo = {
      event: eventName
    }][0];
    actionInfo.event = (actionInfo.event || actionType).toLowerCase();
    eventName = actionInfo.event;
    assert$1(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));

    if (!actions[actionType]) {
      actions[actionType] = {
        action: action,
        actionInfo: actionInfo
      };
    }

    eventActionMap[eventName] = actionType;
  }

  function registerCoordinateSystem(type, coordSysCreator) {
    CoordinateSystemManager.register(type, coordSysCreator);
  }

  function getCoordinateSystemDimensions(type) {
    var coordSysCreator = CoordinateSystemManager.get(type);

    if (coordSysCreator) {
      return coordSysCreator.getDimensionsInfo ? coordSysCreator.getDimensionsInfo() : coordSysCreator.dimensions.slice();
    }
  }

  function registerLayout(priority, layoutTask) {
    normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout');
  }

  function registerVisual(priority, visualTask) {
    normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual');
  }

  function normalizeRegister(targetList, priority, fn, defaultPriority, visualType) {
    if (isFunction$1(priority) || isObject$2(priority)) {
      fn = priority;
      priority = defaultPriority;
    }

    if (true) {
      if (isNaN(priority) || priority == null) {
        throw new Error('Illegal priority');
      }

      each$3(targetList, function (wrap) {
        assert$1(wrap.__raw !== fn);
      });
    }

    var stageHandler = Scheduler.wrapStageHandler(fn, visualType);
    stageHandler.__prio = priority;
    stageHandler.__raw = fn;
    targetList.push(stageHandler);
  }

  function registerLoading(name, loadingFx) {
    loadingEffects[name] = loadingFx;
  }

  function extendComponentModel(proto) {
    return ComponentModel.extend(proto);
  }

  function extendComponentView(proto) {
    return ComponentView.extend(proto);
  }

  function extendSeriesModel(proto) {
    return SeriesModel.extend(proto);
  }

  function extendChartView(proto) {
    return ChartView.extend(proto);
  }

  function setCanvasCreator(creator) {
    $override('createCanvas', creator);
  }

  function registerMap(mapName, geoJson, specialAreas) {
    mapDataStorage.registerMap(mapName, geoJson, specialAreas);
  }

  function getMap(mapName) {
    var records = mapDataStorage.retrieveMap(mapName);
    return records && records[0] && {
      geoJson: records[0].geoJSON,
      specialAreas: records[0].specialAreas
    };
  }

  var registerTransform = registerExternalTransform;
  registerVisual(PRIORITY_VISUAL_GLOBAL, seriesStyleTask);
  registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataStyleTask);
  registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataColorPaletteTask);
  registerVisual(PRIORITY_VISUAL_GLOBAL, seriesSymbolTask);
  registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataSymbolTask);
  registerPreprocessor(backwardCompat);
  registerProcessor(PRIORITY_PROCESSOR_DATASTACK, dataStack);
  registerLoading('default', loadingDefault);
  registerAction({
    type: HIGHLIGHT_ACTION_TYPE,
    event: HIGHLIGHT_ACTION_TYPE,
    update: HIGHLIGHT_ACTION_TYPE
  }, noop);
  registerAction({
    type: DOWNPLAY_ACTION_TYPE,
    event: DOWNPLAY_ACTION_TYPE,
    update: DOWNPLAY_ACTION_TYPE
  }, noop);
  registerAction({
    type: SELECT_ACTION_TYPE,
    event: SELECT_ACTION_TYPE,
    update: SELECT_ACTION_TYPE
  }, noop);
  registerAction({
    type: UNSELECT_ACTION_TYPE,
    event: UNSELECT_ACTION_TYPE,
    update: UNSELECT_ACTION_TYPE
  }, noop);
  registerAction({
    type: TOGGLE_SELECT_ACTION_TYPE,
    event: TOGGLE_SELECT_ACTION_TYPE,
    update: TOGGLE_SELECT_ACTION_TYPE
  }, noop);
  registerTheme('light', lightTheme);
  registerTheme('dark', theme);
  var dataTool = {};

  function defaultKeyGetter(item) {
    return item;
  }

  var DataDiffer = function () {
    function DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context) {
      this._old = oldArr;
      this._new = newArr;
      this._oldKeyGetter = oldKeyGetter || defaultKeyGetter;
      this._newKeyGetter = newKeyGetter || defaultKeyGetter;
      this.context = context;
    }

    DataDiffer.prototype.add = function (func) {
      this._add = func;
      return this;
    };

    DataDiffer.prototype.update = function (func) {
      this._update = func;
      return this;
    };

    DataDiffer.prototype.remove = function (func) {
      this._remove = func;
      return this;
    };

    DataDiffer.prototype.execute = function () {
      var oldArr = this._old;
      var newArr = this._new;
      var oldDataIndexMap = {};
      var newDataIndexMap = {};
      var oldDataKeyArr = [];
      var newDataKeyArr = [];
      var i;

      this._initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter');

      this._initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter');

      for (i = 0; i < oldArr.length; i++) {
        var key = oldDataKeyArr[i];
        var idx = newDataIndexMap[key];

        if (idx != null) {
          var len = idx.length;

          if (len) {
            len === 1 && (newDataIndexMap[key] = null);
            idx = idx.shift();
          } else {
            newDataIndexMap[key] = null;
          }

          this._update && this._update(idx, i);
        } else {
          this._remove && this._remove(i);
        }
      }

      for (i = 0; i < newDataKeyArr.length; i++) {
        var key = newDataKeyArr[i];

        if (newDataIndexMap.hasOwnProperty(key)) {
          var idx = newDataIndexMap[key];

          if (idx == null) {
            continue;
          }

          if (!idx.length) {
            this._add && this._add(idx);
          } else {
            for (var j = 0, len = idx.length; j < len; j++) {
              this._add && this._add(idx[j]);
            }
          }
        }
      }
    };

    DataDiffer.prototype._initIndexMap = function (arr, map, keyArr, keyGetterName) {
      for (var i = 0; i < arr.length; i++) {
        var key = '_ec_' + this[keyGetterName](arr[i], i);
        var existence = map[key];

        if (existence == null) {
          keyArr.push(key);
          map[key] = i;
        } else {
          if (!existence.length) {
            map[key] = existence = [existence];
          }

          existence.push(i);
        }
      }
    };

    return DataDiffer;
  }();

  function summarizeDimensions(data) {
    var summary = {};
    var encode = summary.encode = {};
    var notExtraCoordDimMap = createHashMap();
    var defaultedLabel = [];
    var defaultedTooltip = [];
    var userOutput = summary.userOutput = {
      dimensionNames: data.dimensions.slice(),
      encode: {}
    };
    each(data.dimensions, function (dimName) {
      var dimItem = data.getDimensionInfo(dimName);
      var coordDim = dimItem.coordDim;

      if (coordDim) {
        if (true) {
          assert(VISUAL_DIMENSIONS.get(coordDim) == null);
        }

        var coordDimIndex = dimItem.coordDimIndex;
        getOrCreateEncodeArr(encode, coordDim)[coordDimIndex] = dimName;

        if (!dimItem.isExtraCoord) {
          notExtraCoordDimMap.set(coordDim, 1);

          if (mayLabelDimType(dimItem.type)) {
            defaultedLabel[0] = dimName;
          }

          getOrCreateEncodeArr(userOutput.encode, coordDim)[coordDimIndex] = dimItem.index;
        }

        if (dimItem.defaultTooltip) {
          defaultedTooltip.push(dimName);
        }
      }

      VISUAL_DIMENSIONS.each(function (v, otherDim) {
        var encodeArr = getOrCreateEncodeArr(encode, otherDim);
        var dimIndex = dimItem.otherDims[otherDim];

        if (dimIndex != null && dimIndex !== false) {
          encodeArr[dimIndex] = dimItem.name;
        }
      });
    });
    var dataDimsOnCoord = [];
    var encodeFirstDimNotExtra = {};
    notExtraCoordDimMap.each(function (v, coordDim) {
      var dimArr = encode[coordDim];
      encodeFirstDimNotExtra[coordDim] = dimArr[0];
      dataDimsOnCoord = dataDimsOnCoord.concat(dimArr);
    });
    summary.dataDimsOnCoord = dataDimsOnCoord;
    summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra;
    var encodeLabel = encode.label;

    if (encodeLabel && encodeLabel.length) {
      defaultedLabel = encodeLabel.slice();
    }

    var encodeTooltip = encode.tooltip;

    if (encodeTooltip && encodeTooltip.length) {
      defaultedTooltip = encodeTooltip.slice();
    } else if (!defaultedTooltip.length) {
      defaultedTooltip = defaultedLabel.slice();
    }

    encode.defaultedLabel = defaultedLabel;
    encode.defaultedTooltip = defaultedTooltip;
    return summary;
  }

  function getOrCreateEncodeArr(encode, dim) {
    if (!encode.hasOwnProperty(dim)) {
      encode[dim] = [];
    }

    return encode[dim];
  }

  function getDimensionTypeByAxis(axisType) {
    return axisType === 'category' ? 'ordinal' : axisType === 'time' ? 'time' : 'float';
  }

  function mayLabelDimType(dimType) {
    return !(dimType === 'ordinal' || dimType === 'time');
  }

  var DataDimensionInfo = function () {
    function DataDimensionInfo(opt) {
      this.otherDims = {};

      if (opt != null) {
        extend(this, opt);
      }
    }

    return DataDimensionInfo;
  }();

  var isObject$3 = isObject;
  var UNDEFINED = 'undefined';
  var INDEX_NOT_FOUND = -1;
  var ID_PREFIX = 'e\0\0';
  var dataCtors = {
    'float': typeof Float64Array === UNDEFINED ? Array : Float64Array,
    'int': typeof Int32Array === UNDEFINED ? Array : Int32Array,
    'ordinal': Array,
    'number': Array,
    'time': Array
  };
  var CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array;
  var CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array;
  var CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array;
  var TRANSFERABLE_PROPERTIES = ['hasItemOption', '_nameList', '_idList', '_invertedIndicesMap', '_rawData', '_chunkSize', '_chunkCount', '_dimValueGetter', '_count', '_rawCount', '_nameDimIdx', '_idDimIdx'];
  var CLONE_PROPERTIES = ['_extent', '_approximateExtent', '_rawExtent'];
  var defaultDimValueGetters;
  var prepareInvertedIndex;
  var getRawValueFromStore;
  var getIndicesCtor;
  var prepareChunks;
  var getRawIndexWithoutIndices;
  var getRawIndexWithIndices;
  var getId;
  var normalizeDimensions;
  var validateDimensions;
  var cloneListForMapAndSample;
  var cloneDimStore;
  var getInitialExtent;
  var setItemDataAndSeriesIndex;
  var transferProperties;

  var List = function () {
    function List(dimensions, hostModel) {
      this.type = 'list';
      this._count = 0;
      this._rawCount = 0;
      this._storage = {};
      this._nameList = [];
      this._idList = [];
      this._visual = {};
      this._layout = {};
      this._itemVisuals = [];
      this._itemLayouts = [];
      this._graphicEls = [];
      this._chunkSize = 1e5;
      this._chunkCount = 0;
      this._rawExtent = {};
      this._extent = {};
      this._approximateExtent = {};
      this._calculationInfo = {};
      this.hasItemOption = true;
      this.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'map'];
      this.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];
      this.getRawIndex = getRawIndexWithoutIndices;
      dimensions = dimensions || ['x', 'y'];
      var dimensionInfos = {};
      var dimensionNames = [];
      var invertedIndicesMap = {};

      for (var i = 0; i < dimensions.length; i++) {
        var dimInfoInput = dimensions[i];
        var dimensionInfo = isString(dimInfoInput) ? new DataDimensionInfo({
          name: dimInfoInput
        }) : !(dimInfoInput instanceof DataDimensionInfo) ? new DataDimensionInfo(dimInfoInput) : dimInfoInput;
        var dimensionName = dimensionInfo.name;
        dimensionInfo.type = dimensionInfo.type || 'float';

        if (!dimensionInfo.coordDim) {
          dimensionInfo.coordDim = dimensionName;
          dimensionInfo.coordDimIndex = 0;
        }

        dimensionInfo.otherDims = dimensionInfo.otherDims || {};
        dimensionNames.push(dimensionName);
        dimensionInfos[dimensionName] = dimensionInfo;
        dimensionInfo.index = i;

        if (dimensionInfo.createInvertedIndices) {
          invertedIndicesMap[dimensionName] = [];
        }
      }

      this.dimensions = dimensionNames;
      this._dimensionInfos = dimensionInfos;
      this.hostModel = hostModel;
      this._dimensionsSummary = summarizeDimensions(this);
      this._invertedIndicesMap = invertedIndicesMap;
      this.userOutput = this._dimensionsSummary.userOutput;
    }

    List.prototype.getDimension = function (dim) {
      if (typeof dim === 'number' || !isNaN(dim) && !this._dimensionInfos.hasOwnProperty(dim)) {
        dim = this.dimensions[dim];
      }

      return dim;
    };

    List.prototype.getDimensionInfo = function (dim) {
      return this._dimensionInfos[this.getDimension(dim)];
    };

    List.prototype.getDimensionsOnCoord = function () {
      return this._dimensionsSummary.dataDimsOnCoord.slice();
    };

    List.prototype.mapDimension = function (coordDim, idx) {
      var dimensionsSummary = this._dimensionsSummary;

      if (idx == null) {
        return dimensionsSummary.encodeFirstDimNotExtra[coordDim];
      }

      var dims = dimensionsSummary.encode[coordDim];
      return dims ? dims[idx] : null;
    };

    List.prototype.mapDimensionsAll = function (coordDim) {
      var dimensionsSummary = this._dimensionsSummary;
      var dims = dimensionsSummary.encode[coordDim];
      return (dims || []).slice();
    };

    List.prototype.initData = function (data, nameList, dimValueGetter) {
      var notProvider = data instanceof Source || isArrayLike(data);

      if (notProvider) {
        data = new DefaultDataProvider(data, this.dimensions.length);
      }

      if (true) {
        if (!notProvider && (typeof data.getItem !== 'function' || typeof data.count !== 'function')) {
          throw new Error('Inavlid data provider.');
        }
      }

      this._rawData = data;
      this._storage = {};
      this._indices = null;
      this._nameList = nameList || [];
      this._idList = [];
      this._nameRepeatCount = {};

      if (!dimValueGetter) {
        this.hasItemOption = false;
      }

      this.defaultDimValueGetter = defaultDimValueGetters[this._rawData.getSource().sourceFormat];
      this._dimValueGetter = dimValueGetter = dimValueGetter || this.defaultDimValueGetter;
      this._dimValueGetterArrayRows = defaultDimValueGetters.arrayRows;
      this._rawExtent = {};

      this._initDataFromProvider(0, data.count());

      if (data.pure) {
        this.hasItemOption = false;
      }
    };

    List.prototype.getProvider = function () {
      return this._rawData;
    };

    List.prototype.appendData = function (data) {
      if (true) {
        assert(!this._indices, 'appendData can only be called on raw data.');
      }

      var rawData = this._rawData;
      var start = this.count();
      rawData.appendData(data);
      var end = rawData.count();

      if (!rawData.persistent) {
        end += start;
      }

      this._initDataFromProvider(start, end);
    };

    List.prototype.appendValues = function (values, names) {
      var chunkSize = this._chunkSize;
      var storage = this._storage;
      var dimensions = this.dimensions;
      var dimLen = dimensions.length;
      var rawExtent = this._rawExtent;
      var start = this.count();
      var end = start + Math.max(values.length, names ? names.length : 0);
      var originalChunkCount = this._chunkCount;

      for (var i = 0; i < dimLen; i++) {
        var dim = dimensions[i];

        if (!rawExtent[dim]) {
          rawExtent[dim] = getInitialExtent();
        }

        if (!storage[dim]) {
          storage[dim] = [];
        }

        prepareChunks(storage, this._dimensionInfos[dim], chunkSize, originalChunkCount, end);
        this._chunkCount = storage[dim].length;
      }

      var emptyDataItem = new Array(dimLen);

      for (var idx = start; idx < end; idx++) {
        var sourceIdx = idx - start;
        var chunkIndex = Math.floor(idx / chunkSize);
        var chunkOffset = idx % chunkSize;

        for (var k = 0; k < dimLen; k++) {
          var dim = dimensions[k];

          var val = this._dimValueGetterArrayRows(values[sourceIdx] || emptyDataItem, dim, sourceIdx, k);

          storage[dim][chunkIndex][chunkOffset] = val;
          var dimRawExtent = rawExtent[dim];
          val < dimRawExtent[0] && (dimRawExtent[0] = val);
          val > dimRawExtent[1] && (dimRawExtent[1] = val);
        }

        if (names) {
          this._nameList[idx] = names[sourceIdx];
        }
      }

      this._rawCount = this._count = end;
      this._extent = {};
      prepareInvertedIndex(this);
    };

    List.prototype._initDataFromProvider = function (start, end) {
      if (start >= end) {
        return;
      }

      var chunkSize = this._chunkSize;
      var rawData = this._rawData;
      var storage = this._storage;
      var dimensions = this.dimensions;
      var dimLen = dimensions.length;
      var dimensionInfoMap = this._dimensionInfos;
      var nameList = this._nameList;
      var idList = this._idList;
      var rawExtent = this._rawExtent;
      var nameRepeatCount = this._nameRepeatCount = {};
      var nameDimIdx;
      var originalChunkCount = this._chunkCount;

      for (var i = 0; i < dimLen; i++) {
        var dim = dimensions[i];

        if (!rawExtent[dim]) {
          rawExtent[dim] = getInitialExtent();
        }

        var dimInfo = dimensionInfoMap[dim];

        if (dimInfo.otherDims.itemName === 0) {
          nameDimIdx = this._nameDimIdx = i;
        }

        if (dimInfo.otherDims.itemId === 0) {
          this._idDimIdx = i;
        }

        if (!storage[dim]) {
          storage[dim] = [];
        }

        prepareChunks(storage, dimInfo, chunkSize, originalChunkCount, end);
        this._chunkCount = storage[dim].length;
      }

      var dataItem = new Array(dimLen);

      for (var idx = start; idx < end; idx++) {
        dataItem = rawData.getItem(idx, dataItem);
        var chunkIndex = Math.floor(idx / chunkSize);
        var chunkOffset = idx % chunkSize;

        for (var k = 0; k < dimLen; k++) {
          var dim = dimensions[k];
          var dimStorage = storage[dim][chunkIndex];

          var val = this._dimValueGetter(dataItem, dim, idx, k);

          dimStorage[chunkOffset] = val;
          var dimRawExtent = rawExtent[dim];
          val < dimRawExtent[0] && (dimRawExtent[0] = val);
          val > dimRawExtent[1] && (dimRawExtent[1] = val);
        }

        if (!rawData.pure) {
          var name_1 = nameList[idx];

          if (dataItem && name_1 == null) {
            if (dataItem.name != null) {
              nameList[idx] = name_1 = dataItem.name;
            } else if (nameDimIdx != null) {
              var nameDim = dimensions[nameDimIdx];
              var nameDimChunk = storage[nameDim][chunkIndex];

              if (nameDimChunk) {
                name_1 = nameDimChunk[chunkOffset];
                var ordinalMeta = dimensionInfoMap[nameDim].ordinalMeta;

                if (ordinalMeta && ordinalMeta.categories.length) {
                  name_1 = ordinalMeta.categories[name_1];
                }
              }
            }
          }

          var id = dataItem == null ? null : dataItem.id;

          if (id == null && name_1 != null) {
            nameRepeatCount[name_1] = nameRepeatCount[name_1] || 0;
            id = name_1;

            if (nameRepeatCount[name_1] > 0) {
              id += '__ec__' + nameRepeatCount[name_1];
            }

            nameRepeatCount[name_1]++;
          }

          id != null && (idList[idx] = id);
        }
      }

      if (!rawData.persistent && rawData.clean) {
        rawData.clean();
      }

      this._rawCount = this._count = end;
      this._extent = {};
      prepareInvertedIndex(this);
    };

    List.prototype.count = function () {
      return this._count;
    };

    List.prototype.getIndices = function () {
      var newIndices;
      var indices = this._indices;

      if (indices) {
        var Ctor = indices.constructor;
        var thisCount = this._count;

        if (Ctor === Array) {
          newIndices = new Ctor(thisCount);

          for (var i = 0; i < thisCount; i++) {
            newIndices[i] = indices[i];
          }
        } else {
          newIndices = new Ctor(indices.buffer, 0, thisCount);
        }
      } else {
        var Ctor = getIndicesCtor(this);
        newIndices = new Ctor(this.count());

        for (var i = 0; i < newIndices.length; i++) {
          newIndices[i] = i;
        }
      }

      return newIndices;
    };

    List.prototype.get = function (dim, idx) {
      if (!(idx >= 0 && idx < this._count)) {
        return NaN;
      }

      var storage = this._storage;

      if (!storage[dim]) {
        return NaN;
      }

      idx = this.getRawIndex(idx);
      var chunkIndex = Math.floor(idx / this._chunkSize);
      var chunkOffset = idx % this._chunkSize;
      var chunkStore = storage[dim][chunkIndex];
      var value = chunkStore[chunkOffset];
      return value;
    };

    List.prototype.getByRawIndex = function (dim, rawIdx) {
      if (!(rawIdx >= 0 && rawIdx < this._rawCount)) {
        return NaN;
      }

      var dimStore = this._storage[dim];

      if (!dimStore) {
        return NaN;
      }

      var chunkIndex = Math.floor(rawIdx / this._chunkSize);
      var chunkOffset = rawIdx % this._chunkSize;
      var chunkStore = dimStore[chunkIndex];
      return chunkStore[chunkOffset];
    };

    List.prototype._getFast = function (dim, rawIdx) {
      var chunkIndex = Math.floor(rawIdx / this._chunkSize);
      var chunkOffset = rawIdx % this._chunkSize;
      var chunkStore = this._storage[dim][chunkIndex];
      return chunkStore[chunkOffset];
    };

    List.prototype.getValues = function (dimensions, idx) {
      var values = [];

      if (!isArray(dimensions)) {
        idx = dimensions;
        dimensions = this.dimensions;
      }

      for (var i = 0, len = dimensions.length; i < len; i++) {
        values.push(this.get(dimensions[i], idx));
      }

      return values;
    };

    List.prototype.hasValue = function (idx) {
      var dataDimsOnCoord = this._dimensionsSummary.dataDimsOnCoord;

      for (var i = 0, len = dataDimsOnCoord.length; i < len; i++) {
        if (isNaN(this.get(dataDimsOnCoord[i], idx))) {
          return false;
        }
      }

      return true;
    };

    List.prototype.getDataExtent = function (dim) {
      dim = this.getDimension(dim);
      var dimData = this._storage[dim];
      var initialExtent = getInitialExtent();

      if (!dimData) {
        return initialExtent;
      }

      var currEnd = this.count();
      var useRaw = !this._indices;
      var dimExtent;

      if (useRaw) {
        return this._rawExtent[dim].slice();
      }

      dimExtent = this._extent[dim];

      if (dimExtent) {
        return dimExtent.slice();
      }

      dimExtent = initialExtent;
      var min = dimExtent[0];
      var max = dimExtent[1];

      for (var i = 0; i < currEnd; i++) {
        var value = this._getFast(dim, this.getRawIndex(i));

        value < min && (min = value);
        value > max && (max = value);
      }

      dimExtent = [min, max];
      this._extent[dim] = dimExtent;
      return dimExtent;
    };

    List.prototype.getApproximateExtent = function (dim) {
      dim = this.getDimension(dim);
      return this._approximateExtent[dim] || this.getDataExtent(dim);
    };

    List.prototype.setApproximateExtent = function (extent, dim) {
      dim = this.getDimension(dim);
      this._approximateExtent[dim] = extent.slice();
    };

    List.prototype.getCalculationInfo = function (key) {
      return this._calculationInfo[key];
    };

    List.prototype.setCalculationInfo = function (key, value) {
      isObject$3(key) ? extend(this._calculationInfo, key) : this._calculationInfo[key] = value;
    };

    List.prototype.getSum = function (dim) {
      var dimData = this._storage[dim];
      var sum = 0;

      if (dimData) {
        for (var i = 0, len = this.count(); i < len; i++) {
          var value = this.get(dim, i);

          if (!isNaN(value)) {
            sum += value;
          }
        }
      }

      return sum;
    };

    List.prototype.getMedian = function (dim) {
      var dimDataArray = [];
      this.each(dim, function (val) {
        if (!isNaN(val)) {
          dimDataArray.push(val);
        }
      });
      var sortedDimDataArray = dimDataArray.sort(function (a, b) {
        return a - b;
      });
      var len = this.count();
      return len === 0 ? 0 : len % 2 === 1 ? sortedDimDataArray[(len - 1) / 2] : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2;
    };

    List.prototype.rawIndexOf = function (dim, value) {
      var invertedIndices = dim && this._invertedIndicesMap[dim];

      if (true) {
        if (!invertedIndices) {
          throw new Error('Do not supported yet');
        }
      }

      var rawIndex = invertedIndices[value];

      if (rawIndex == null || isNaN(rawIndex)) {
        return INDEX_NOT_FOUND;
      }

      return rawIndex;
    };

    List.prototype.indexOfName = function (name) {
      for (var i = 0, len = this.count(); i < len; i++) {
        if (this.getName(i) === name) {
          return i;
        }
      }

      return -1;
    };

    List.prototype.indexOfRawIndex = function (rawIndex) {
      if (rawIndex >= this._rawCount || rawIndex < 0) {
        return -1;
      }

      if (!this._indices) {
        return rawIndex;
      }

      var indices = this._indices;
      var rawDataIndex = indices[rawIndex];

      if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) {
        return rawIndex;
      }

      var left = 0;
      var right = this._count - 1;

      while (left <= right) {
        var mid = (left + right) / 2 | 0;

        if (indices[mid] < rawIndex) {
          left = mid + 1;
        } else if (indices[mid] > rawIndex) {
          right = mid - 1;
        } else {
          return mid;
        }
      }

      return -1;
    };

    List.prototype.indicesOfNearest = function (dim, value, maxDistance) {
      var storage = this._storage;
      var dimData = storage[dim];
      var nearestIndices = [];

      if (!dimData) {
        return nearestIndices;
      }

      if (maxDistance == null) {
        maxDistance = Infinity;
      }

      var minDist = Infinity;
      var minDiff = -1;
      var nearestIndicesLen = 0;

      for (var i = 0, len = this.count(); i < len; i++) {
        var diff = value - this.get(dim, i);
        var dist = Math.abs(diff);

        if (dist <= maxDistance) {
          if (dist < minDist || dist === minDist && diff >= 0 && minDiff < 0) {
            minDist = dist;
            minDiff = diff;
            nearestIndicesLen = 0;
          }

          if (diff === minDiff) {
            nearestIndices[nearestIndicesLen++] = i;
          }
        }
      }

      nearestIndices.length = nearestIndicesLen;
      return nearestIndices;
    };

    List.prototype.getRawDataItem = function (idx) {
      if (!this._rawData.persistent) {
        var val = [];

        for (var i = 0; i < this.dimensions.length; i++) {
          var dim = this.dimensions[i];
          val.push(this.get(dim, idx));
        }

        return val;
      } else {
        return this._rawData.getItem(this.getRawIndex(idx));
      }
    };

    List.prototype.getName = function (idx) {
      var rawIndex = this.getRawIndex(idx);
      return this._nameList[rawIndex] || getRawValueFromStore(this, this._nameDimIdx, rawIndex) || '';
    };

    List.prototype.getId = function (idx) {
      return getId(this, this.getRawIndex(idx));
    };

    List.prototype.each = function (dims, cb, ctx, ctxCompat) {
      if (!this._count) {
        return;
      }

      if (typeof dims === 'function') {
        ctxCompat = ctx;
        ctx = cb;
        cb = dims;
        dims = [];
      }

      var fCtx = ctx || ctxCompat || this;
      var dimNames = map(normalizeDimensions(dims), this.getDimension, this);

      if (true) {
        validateDimensions(this, dimNames);
      }

      var dimSize = dimNames.length;

      for (var i = 0; i < this.count(); i++) {
        switch (dimSize) {
          case 0:
            cb.call(fCtx, i);
            break;

          case 1:
            cb.call(fCtx, this.get(dimNames[0], i), i);
            break;

          case 2:
            cb.call(fCtx, this.get(dimNames[0], i), this.get(dimNames[1], i), i);
            break;

          default:
            var k = 0;
            var value = [];

            for (; k < dimSize; k++) {
              value[k] = this.get(dimNames[k], i);
            }

            value[k] = i;
            cb.apply(fCtx, value);
        }
      }
    };

    List.prototype.filterSelf = function (dims, cb, ctx, ctxCompat) {
      if (!this._count) {
        return;
      }

      if (typeof dims === 'function') {
        ctxCompat = ctx;
        ctx = cb;
        cb = dims;
        dims = [];
      }

      var fCtx = ctx || ctxCompat || this;
      var dimNames = map(normalizeDimensions(dims), this.getDimension, this);

      if (true) {
        validateDimensions(this, dimNames);
      }

      var count = this.count();
      var Ctor = getIndicesCtor(this);
      var newIndices = new Ctor(count);
      var value = [];
      var dimSize = dimNames.length;
      var offset = 0;
      var dim0 = dimNames[0];

      for (var i = 0; i < count; i++) {
        var keep = void 0;
        var rawIdx = this.getRawIndex(i);

        if (dimSize === 0) {
          keep = cb.call(fCtx, i);
        } else if (dimSize === 1) {
          var val = this._getFast(dim0, rawIdx);

          keep = cb.call(fCtx, val, i);
        } else {
          var k = 0;

          for (; k < dimSize; k++) {
            value[k] = this._getFast(dim0, rawIdx);
          }

          value[k] = i;
          keep = cb.apply(fCtx, value);
        }

        if (keep) {
          newIndices[offset++] = rawIdx;
        }
      }

      if (offset < count) {
        this._indices = newIndices;
      }

      this._count = offset;
      this._extent = {};
      this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;
      return this;
    };

    List.prototype.selectRange = function (range) {
      if (!this._count) {
        return;
      }

      var dimensions = [];

      for (var dim in range) {
        if (range.hasOwnProperty(dim)) {
          dimensions.push(dim);
        }
      }

      if (true) {
        validateDimensions(this, dimensions);
      }

      var dimSize = dimensions.length;

      if (!dimSize) {
        return;
      }

      var originalCount = this.count();
      var Ctor = getIndicesCtor(this);
      var newIndices = new Ctor(originalCount);
      var offset = 0;
      var dim0 = dimensions[0];
      var min = range[dim0][0];
      var max = range[dim0][1];
      var quickFinished = false;

      if (!this._indices) {
        var idx = 0;

        if (dimSize === 1) {
          var dimStorage = this._storage[dimensions[0]];

          for (var k = 0; k < this._chunkCount; k++) {
            var chunkStorage = dimStorage[k];
            var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);

            for (var i = 0; i < len; i++) {
              var val = chunkStorage[i];

              if (val >= min && val <= max || isNaN(val)) {
                newIndices[offset++] = idx;
              }

              idx++;
            }
          }

          quickFinished = true;
        } else if (dimSize === 2) {
          var dimStorage = this._storage[dim0];
          var dimStorage2 = this._storage[dimensions[1]];
          var min2 = range[dimensions[1]][0];
          var max2 = range[dimensions[1]][1];

          for (var k = 0; k < this._chunkCount; k++) {
            var chunkStorage = dimStorage[k];
            var chunkStorage2 = dimStorage2[k];
            var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);

            for (var i = 0; i < len; i++) {
              var val = chunkStorage[i];
              var val2 = chunkStorage2[i];

              if ((val >= min && val <= max || isNaN(val)) && (val2 >= min2 && val2 <= max2 || isNaN(val2))) {
                newIndices[offset++] = idx;
              }

              idx++;
            }
          }

          quickFinished = true;
        }
      }

      if (!quickFinished) {
        if (dimSize === 1) {
          for (var i = 0; i < originalCount; i++) {
            var rawIndex = this.getRawIndex(i);

            var val = this._getFast(dim0, rawIndex);

            if (val >= min && val <= max || isNaN(val)) {
              newIndices[offset++] = rawIndex;
            }
          }
        } else {
          for (var i = 0; i < originalCount; i++) {
            var keep = true;
            var rawIndex = this.getRawIndex(i);

            for (var k = 0; k < dimSize; k++) {
              var dimk = dimensions[k];

              var val = this._getFast(dimk, rawIndex);

              if (val < range[dimk][0] || val > range[dimk][1]) {
                keep = false;
              }
            }

            if (keep) {
              newIndices[offset++] = this.getRawIndex(i);
            }
          }
        }
      }

      if (offset < originalCount) {
        this._indices = newIndices;
      }

      this._count = offset;
      this._extent = {};
      this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;
      return this;
    };

    List.prototype.mapArray = function (dims, cb, ctx, ctxCompat) {
      if (typeof dims === 'function') {
        ctxCompat = ctx;
        ctx = cb;
        cb = dims;
        dims = [];
      }

      ctx = ctx || ctxCompat || this;
      var result = [];
      this.each(dims, function () {
        result.push(cb && cb.apply(this, arguments));
      }, ctx);
      return result;
    };

    List.prototype.map = function (dims, cb, ctx, ctxCompat) {
      var fCtx = ctx || ctxCompat || this;
      var dimNames = map(normalizeDimensions(dims), this.getDimension, this);

      if (true) {
        validateDimensions(this, dimNames);
      }

      var list = cloneListForMapAndSample(this, dimNames);
      list._indices = this._indices;
      list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;
      var storage = list._storage;
      var tmpRetValue = [];
      var chunkSize = this._chunkSize;
      var dimSize = dimNames.length;
      var dataCount = this.count();
      var values = [];
      var rawExtent = list._rawExtent;

      for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) {
        for (var dimIndex = 0; dimIndex < dimSize; dimIndex++) {
          values[dimIndex] = this.get(dimNames[dimIndex], dataIndex);
        }

        values[dimSize] = dataIndex;
        var retValue = cb && cb.apply(fCtx, values);

        if (retValue != null) {
          if (typeof retValue !== 'object') {
            tmpRetValue[0] = retValue;
            retValue = tmpRetValue;
          }

          var rawIndex = this.getRawIndex(dataIndex);
          var chunkIndex = Math.floor(rawIndex / chunkSize);
          var chunkOffset = rawIndex % chunkSize;

          for (var i = 0; i < retValue.length; i++) {
            var dim = dimNames[i];
            var val = retValue[i];
            var rawExtentOnDim = rawExtent[dim];
            var dimStore = storage[dim];

            if (dimStore) {
              dimStore[chunkIndex][chunkOffset] = val;
            }

            if (val < rawExtentOnDim[0]) {
              rawExtentOnDim[0] = val;
            }

            if (val > rawExtentOnDim[1]) {
              rawExtentOnDim[1] = val;
            }
          }
        }
      }

      return list;
    };

    List.prototype.downSample = function (dimension, rate, sampleValue, sampleIndex) {
      var list = cloneListForMapAndSample(this, [dimension]);
      var targetStorage = list._storage;
      var frameValues = [];
      var frameSize = Math.floor(1 / rate);
      var dimStore = targetStorage[dimension];
      var len = this.count();
      var chunkSize = this._chunkSize;
      var rawExtentOnDim = list._rawExtent[dimension];
      var newIndices = new (getIndicesCtor(this))(len);
      var offset = 0;

      for (var i = 0; i < len; i += frameSize) {
        if (frameSize > len - i) {
          frameSize = len - i;
          frameValues.length = frameSize;
        }

        for (var k = 0; k < frameSize; k++) {
          var dataIdx = this.getRawIndex(i + k);
          var originalChunkIndex = Math.floor(dataIdx / chunkSize);
          var originalChunkOffset = dataIdx % chunkSize;
          frameValues[k] = dimStore[originalChunkIndex][originalChunkOffset];
        }

        var value = sampleValue(frameValues);
        var sampleFrameIdx = this.getRawIndex(Math.min(i + sampleIndex(frameValues, value) || 0, len - 1));
        var sampleChunkIndex = Math.floor(sampleFrameIdx / chunkSize);
        var sampleChunkOffset = sampleFrameIdx % chunkSize;
        dimStore[sampleChunkIndex][sampleChunkOffset] = value;

        if (value < rawExtentOnDim[0]) {
          rawExtentOnDim[0] = value;
        }

        if (value > rawExtentOnDim[1]) {
          rawExtentOnDim[1] = value;
        }

        newIndices[offset++] = sampleFrameIdx;
      }

      list._count = offset;
      list._indices = newIndices;
      list.getRawIndex = getRawIndexWithIndices;
      return list;
    };

    List.prototype.getItemModel = function (idx) {
      var hostModel = this.hostModel;
      var dataItem = this.getRawDataItem(idx);
      return new Model(dataItem, hostModel, hostModel && hostModel.ecModel);
    };

    List.prototype.diff = function (otherList) {
      var thisList = this;
      return new DataDiffer(otherList ? otherList.getIndices() : [], this.getIndices(), function (idx) {
        return getId(otherList, idx);
      }, function (idx) {
        return getId(thisList, idx);
      });
    };

    List.prototype.getVisual = function (key) {
      var visual = this._visual;
      return visual && visual[key];
    };

    List.prototype.setVisual = function (kvObj, val) {
      this._visual = this._visual || {};

      if (isObject$3(kvObj)) {
        extend(this._visual, kvObj);
      } else {
        this._visual[kvObj] = val;
      }
    };

    List.prototype.getItemVisual = function (idx, key) {
      var itemVisual = this._itemVisuals[idx];
      var val = itemVisual && itemVisual[key];

      if (val == null) {
        return this.getVisual(key);
      }

      return val;
    };

    List.prototype.ensureUniqueItemVisual = function (idx, key) {
      var itemVisuals = this._itemVisuals;
      var itemVisual = itemVisuals[idx];

      if (!itemVisual) {
        itemVisual = itemVisuals[idx] = {};
      }

      var val = itemVisual[key];

      if (!val) {
        val = this.getVisual(key);

        if (isArray(val)) {
          val = val.slice();
        } else if (isObject$3(val)) {
          val = extend({}, val);
        }

        itemVisual[key] = val;
      }

      return val;
    };

    List.prototype.setItemVisual = function (idx, key, value) {
      var itemVisual = this._itemVisuals[idx] || {};
      this._itemVisuals[idx] = itemVisual;

      if (isObject$3(key)) {
        extend(itemVisual, key);
      } else {
        itemVisual[key] = value;
      }
    };

    List.prototype.clearAllVisual = function () {
      this._visual = {};
      this._itemVisuals = [];
    };

    List.prototype.setLayout = function (key, val) {
      if (isObject$3(key)) {
        for (var name_2 in key) {
          if (key.hasOwnProperty(name_2)) {
            this.setLayout(name_2, key[name_2]);
          }
        }

        return;
      }

      this._layout[key] = val;
    };

    List.prototype.getLayout = function (key) {
      return this._layout[key];
    };

    List.prototype.getItemLayout = function (idx) {
      return this._itemLayouts[idx];
    };

    List.prototype.setItemLayout = function (idx, layout, merge) {
      this._itemLayouts[idx] = merge ? extend(this._itemLayouts[idx] || {}, layout) : layout;
    };

    List.prototype.clearItemLayouts = function () {
      this._itemLayouts.length = 0;
    };

    List.prototype.setItemGraphicEl = function (idx, el) {
      var hostModel = this.hostModel;

      if (el) {
        var ecData = getECData(el);
        ecData.dataIndex = idx;
        ecData.dataType = this.dataType;
        ecData.seriesIndex = hostModel && hostModel.seriesIndex;

        if (el.type === 'group') {
          el.traverse(setItemDataAndSeriesIndex, el);
        }
      }

      this._graphicEls[idx] = el;
    };

    List.prototype.getItemGraphicEl = function (idx) {
      return this._graphicEls[idx];
    };

    List.prototype.eachItemGraphicEl = function (cb, context) {
      each(this._graphicEls, function (el, idx) {
        if (el) {
          cb && cb.call(context, el, idx);
        }
      });
    };

    List.prototype.cloneShallow = function (list) {
      if (!list) {
        var dimensionInfoList = map(this.dimensions, this.getDimensionInfo, this);
        list = new List(dimensionInfoList, this.hostModel);
      }

      list._storage = this._storage;
      transferProperties(list, this);

      if (this._indices) {
        var Ctor = this._indices.constructor;

        if (Ctor === Array) {
          var thisCount = this._indices.length;
          list._indices = new Ctor(thisCount);

          for (var i = 0; i < thisCount; i++) {
            list._indices[i] = this._indices[i];
          }
        } else {
          list._indices = new Ctor(this._indices);
        }
      } else {
        list._indices = null;
      }

      list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;
      return list;
    };

    List.prototype.wrapMethod = function (methodName, injectFunction) {
      var originalMethod = this[methodName];

      if (typeof originalMethod !== 'function') {
        return;
      }

      this.__wrappedMethods = this.__wrappedMethods || [];

      this.__wrappedMethods.push(methodName);

      this[methodName] = function () {
        var res = originalMethod.apply(this, arguments);
        return injectFunction.apply(this, [res].concat(slice(arguments)));
      };
    };

    List.internalField = function () {
      defaultDimValueGetters = {
        arrayRows: getDimValueSimply,
        objectRows: function (dataItem, dimName, dataIndex, dimIndex) {
          return parseDataValue(dataItem[dimName], this._dimensionInfos[dimName]);
        },
        keyedColumns: getDimValueSimply,
        original: function (dataItem, dimName, dataIndex, dimIndex) {
          var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value);

          if (!this._rawData.pure && isDataItemOption(dataItem)) {
            this.hasItemOption = true;
          }

          return parseDataValue(value instanceof Array ? value[dimIndex] : value, this._dimensionInfos[dimName]);
        },
        typedArray: function (dataItem, dimName, dataIndex, dimIndex) {
          return dataItem[dimIndex];
        }
      };

      function getDimValueSimply(dataItem, dimName, dataIndex, dimIndex) {
        return parseDataValue(dataItem[dimIndex], this._dimensionInfos[dimName]);
      }

      prepareInvertedIndex = function (list) {
        var invertedIndicesMap = list._invertedIndicesMap;
        each(invertedIndicesMap, function (invertedIndices, dim) {
          var dimInfo = list._dimensionInfos[dim];
          var ordinalMeta = dimInfo.ordinalMeta;

          if (ordinalMeta) {
            invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(ordinalMeta.categories.length);

            for (var i = 0; i < invertedIndices.length; i++) {
              invertedIndices[i] = INDEX_NOT_FOUND;
            }

            for (var i = 0; i < list._count; i++) {
              invertedIndices[list.get(dim, i)] = i;
            }
          }
        });
      };

      getRawValueFromStore = function (list, dimIndex, rawIndex) {
        var val;

        if (dimIndex != null) {
          var chunkSize = list._chunkSize;
          var chunkIndex = Math.floor(rawIndex / chunkSize);
          var chunkOffset = rawIndex % chunkSize;
          var dim = list.dimensions[dimIndex];
          var chunk = list._storage[dim][chunkIndex];

          if (chunk) {
            val = chunk[chunkOffset];
            var ordinalMeta = list._dimensionInfos[dim].ordinalMeta;

            if (ordinalMeta && ordinalMeta.categories.length) {
              val = ordinalMeta.categories[val];
            }
          }
        }

        return val;
      };

      getIndicesCtor = function (list) {
        return list._rawCount > 65535 ? CtorUint32Array : CtorUint16Array;
      };

      prepareChunks = function (storage, dimInfo, chunkSize, chunkCount, end) {
        var DataCtor = dataCtors[dimInfo.type];
        var lastChunkIndex = chunkCount - 1;
        var dim = dimInfo.name;
        var resizeChunkArray = storage[dim][lastChunkIndex];

        if (resizeChunkArray && resizeChunkArray.length < chunkSize) {
          var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));

          for (var j = 0; j < resizeChunkArray.length; j++) {
            newStore[j] = resizeChunkArray[j];
          }

          storage[dim][lastChunkIndex] = newStore;
        }

        for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {
          storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));
        }
      };

      getRawIndexWithoutIndices = function (idx) {
        return idx;
      };

      getRawIndexWithIndices = function (idx) {
        if (idx < this._count && idx >= 0) {
          return this._indices[idx];
        }

        return -1;
      };

      getId = function (list, rawIndex) {
        var id = list._idList[rawIndex];

        if (id == null) {
          id = getRawValueFromStore(list, list._idDimIdx, rawIndex);
        }

        if (id == null) {
          id = ID_PREFIX + rawIndex;
        }

        return id;
      };

      normalizeDimensions = function (dimensions) {
        if (!isArray(dimensions)) {
          dimensions = [dimensions];
        }

        return dimensions;
      };

      validateDimensions = function (list, dims) {
        for (var i = 0; i < dims.length; i++) {
          if (!list._dimensionInfos[dims[i]]) {
            console.error('Unkown dimension ' + dims[i]);
          }
        }
      };

      cloneListForMapAndSample = function (original, excludeDimensions) {
        var allDimensions = original.dimensions;
        var list = new List(map(allDimensions, original.getDimensionInfo, original), original.hostModel);
        transferProperties(list, original);
        var storage = list._storage = {};
        var originalStorage = original._storage;

        for (var i = 0; i < allDimensions.length; i++) {
          var dim = allDimensions[i];

          if (originalStorage[dim]) {
            if (indexOf(excludeDimensions, dim) >= 0) {
              storage[dim] = cloneDimStore(originalStorage[dim]);
              list._rawExtent[dim] = getInitialExtent();
              list._extent[dim] = null;
            } else {
              storage[dim] = originalStorage[dim];
            }
          }
        }

        return list;
      };

      cloneDimStore = function (originalDimStore) {
        var newDimStore = new Array(originalDimStore.length);

        for (var j = 0; j < originalDimStore.length; j++) {
          newDimStore[j] = cloneChunk(originalDimStore[j]);
        }

        return newDimStore;
      };

      function cloneChunk(originalChunk) {
        var Ctor = originalChunk.constructor;
        return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk);
      }

      getInitialExtent = function () {
        return [Infinity, -Infinity];
      };

      setItemDataAndSeriesIndex = function (child) {
        var childECData = getECData(child);
        var thisECData = getECData(this);
        childECData.seriesIndex = thisECData.seriesIndex;
        childECData.dataIndex = thisECData.dataIndex;
        childECData.dataType = thisECData.dataType;
      };

      transferProperties = function (target, source) {
        each(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) {
          if (source.hasOwnProperty(propName)) {
            target[propName] = source[propName];
          }
        });
        target.__wrappedMethods = source.__wrappedMethods;
        each(CLONE_PROPERTIES, function (propName) {
          target[propName] = clone(source[propName]);
        });
        target._calculationInfo = extend({}, source._calculationInfo);
      };
    }();

    return List;
  }();

  function completeDimensions(sysDims, source, opt) {
    if (!(source instanceof Source)) {
      source = Source.seriesDataToSource(source);
    }

    opt = opt || {};
    sysDims = (sysDims || []).slice();
    var dimsDef = (opt.dimsDef || []).slice();
    var dataDimNameMap = createHashMap();
    var coordDimNameMap = createHashMap();
    var result = [];
    var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount);

    for (var i = 0; i < dimCount; i++) {
      var dimDefItemRaw = dimsDef[i];
      var dimDefItem = dimsDef[i] = extend({}, isObject(dimDefItemRaw) ? dimDefItemRaw : {
        name: dimDefItemRaw
      });
      var userDimName = dimDefItem.name;
      var resultItem = result[i] = new DataDimensionInfo();

      if (userDimName != null && dataDimNameMap.get(userDimName) == null) {
        resultItem.name = resultItem.displayName = userDimName;
        dataDimNameMap.set(userDimName, i);
      }

      dimDefItem.type != null && (resultItem.type = dimDefItem.type);
      dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
    }

    var encodeDef = opt.encodeDef;

    if (!encodeDef && opt.encodeDefaulter) {
      encodeDef = opt.encodeDefaulter(source, dimCount);
    }

    var encodeDefMap = createHashMap(encodeDef);
    encodeDefMap.each(function (dataDimsRaw, coordDim) {
      var dataDims = normalizeToArray(dataDimsRaw).slice();

      if (dataDims.length === 1 && !isString(dataDims[0]) && dataDims[0] < 0) {
        encodeDefMap.set(coordDim, false);
        return;
      }

      var validDataDims = encodeDefMap.set(coordDim, []);
      each(dataDims, function (resultDimIdxOrName, idx) {
        var resultDimIdx = isString(resultDimIdxOrName) ? dataDimNameMap.get(resultDimIdxOrName) : resultDimIdxOrName;

        if (resultDimIdx != null && resultDimIdx < dimCount) {
          validDataDims[idx] = resultDimIdx;
          applyDim(result[resultDimIdx], coordDim, idx);
        }
      });
    });
    var availDimIdx = 0;
    each(sysDims, function (sysDimItemRaw) {
      var coordDim;
      var sysDimItemDimsDef;
      var sysDimItemOtherDims;
      var sysDimItem;

      if (isString(sysDimItemRaw)) {
        coordDim = sysDimItemRaw;
        sysDimItem = {};
      } else {
        sysDimItem = sysDimItemRaw;
        coordDim = sysDimItem.name;
        var ordinalMeta = sysDimItem.ordinalMeta;
        sysDimItem.ordinalMeta = null;
        sysDimItem = clone(sysDimItem);
        sysDimItem.ordinalMeta = ordinalMeta;
        sysDimItemDimsDef = sysDimItem.dimsDef;
        sysDimItemOtherDims = sysDimItem.otherDims;
        sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex = sysDimItem.dimsDef = sysDimItem.otherDims = null;
      }

      var dataDims = encodeDefMap.get(coordDim);

      if (dataDims === false) {
        return;
      }

      dataDims = normalizeToArray(dataDims);

      if (!dataDims.length) {
        for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {
          while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {
            availDimIdx++;
          }

          availDimIdx < result.length && dataDims.push(availDimIdx++);
        }
      }

      each(dataDims, function (resultDimIdx, coordDimIndex) {
        var resultItem = result[resultDimIdx];
        applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);

        if (resultItem.name == null && sysDimItemDimsDef) {
          var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];
          !isObject(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {
            name: sysDimItemDimsDefItem
          });
          resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;
          resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;
        }

        sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);
      });
    });

    function applyDim(resultItem, coordDim, coordDimIndex) {
      if (VISUAL_DIMENSIONS.get(coordDim) != null) {
        resultItem.otherDims[coordDim] = coordDimIndex;
      } else {
        resultItem.coordDim = coordDim;
        resultItem.coordDimIndex = coordDimIndex;
        coordDimNameMap.set(coordDim, true);
      }
    }

    var generateCoord = opt.generateCoord;
    var generateCoordCount = opt.generateCoordCount;
    var fromZero = generateCoordCount != null;
    generateCoordCount = generateCoord ? generateCoordCount || 1 : 0;
    var extra = generateCoord || 'value';

    for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
      var resultItem = result[resultDimIdx] = result[resultDimIdx] || new DataDimensionInfo();
      var coordDim = resultItem.coordDim;

      if (coordDim == null) {
        resultItem.coordDim = genName(extra, coordDimNameMap, fromZero);
        resultItem.coordDimIndex = 0;

        if (!generateCoord || generateCoordCount <= 0) {
          resultItem.isExtraCoord = true;
        }

        generateCoordCount--;
      }

      resultItem.name == null && (resultItem.name = genName(resultItem.coordDim, dataDimNameMap, false));

      if (resultItem.type == null && (guessOrdinal(source, resultDimIdx) === BE_ORDINAL.Must || resultItem.isExtraCoord && (resultItem.otherDims.itemName != null || resultItem.otherDims.seriesName != null))) {
        resultItem.type = 'ordinal';
      }
    }

    return result;
  }

  function getDimCount(source, sysDims, dimsDef, optDimCount) {
    var dimCount = Math.max(source.dimensionsDetectCount || 1, sysDims.length, dimsDef.length, optDimCount || 0);
    each(sysDims, function (sysDimItem) {
      var sysDimItemDimsDef;

      if (isObject(sysDimItem) && (sysDimItemDimsDef = sysDimItem.dimsDef)) {
        dimCount = Math.max(dimCount, sysDimItemDimsDef.length);
      }
    });
    return dimCount;
  }

  function genName(name, map, fromZero) {
    if (fromZero || map.get(name) != null) {
      var i = 0;

      while (map.get(name + i) != null) {
        i++;
      }

      name += i;
    }

    map.set(name, true);
    return name;
  }

  function createDimensions(source, opt) {
    opt = opt || {};
    return completeDimensions(opt.coordDimensions || [], source, {
      dimsDef: opt.dimensionsDefine || source.dimensionsDefine,
      encodeDef: opt.encodeDefine || source.encodeDefine,
      dimCount: opt.dimensionsCount,
      encodeDefaulter: opt.encodeDefaulter,
      generateCoord: opt.generateCoord,
      generateCoordCount: opt.generateCoordCount
    });
  }

  var CoordSysInfo = function () {
    function CoordSysInfo(coordSysName) {
      this.coordSysDims = [];
      this.axisMap = createHashMap();
      this.categoryAxisMap = createHashMap();
      this.coordSysName = coordSysName;
    }

    return CoordSysInfo;
  }();

  function getCoordSysInfoBySeries(seriesModel) {
    var coordSysName = seriesModel.get('coordinateSystem');
    var result = new CoordSysInfo(coordSysName);
    var fetch = fetchers[coordSysName];

    if (fetch) {
      fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);
      return result;
    }
  }

  var fetchers = {
    cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {
      var xAxisModel = seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0];
      var yAxisModel = seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0];

      if (true) {
        if (!xAxisModel) {
          throw new Error('xAxis "' + retrieve(seriesModel.get('xAxisIndex'), seriesModel.get('xAxisId'), 0) + '" not found');
        }

        if (!yAxisModel) {
          throw new Error('yAxis "' + retrieve(seriesModel.get('xAxisIndex'), seriesModel.get('yAxisId'), 0) + '" not found');
        }
      }

      result.coordSysDims = ['x', 'y'];
      axisMap.set('x', xAxisModel);
      axisMap.set('y', yAxisModel);

      if (isCategory(xAxisModel)) {
        categoryAxisMap.set('x', xAxisModel);
        result.firstCategoryDimIndex = 0;
      }

      if (isCategory(yAxisModel)) {
        categoryAxisMap.set('y', yAxisModel);
        result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1);
      }
    },
    singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {
      var singleAxisModel = seriesModel.getReferringComponents('singleAxis', SINGLE_REFERRING).models[0];

      if (true) {
        if (!singleAxisModel) {
          throw new Error('singleAxis should be specified.');
        }
      }

      result.coordSysDims = ['single'];
      axisMap.set('single', singleAxisModel);

      if (isCategory(singleAxisModel)) {
        categoryAxisMap.set('single', singleAxisModel);
        result.firstCategoryDimIndex = 0;
      }
    },
    polar: function (seriesModel, result, axisMap, categoryAxisMap) {
      var polarModel = seriesModel.getReferringComponents('polar', SINGLE_REFERRING).models[0];
      var radiusAxisModel = polarModel.findAxisModel('radiusAxis');
      var angleAxisModel = polarModel.findAxisModel('angleAxis');

      if (true) {
        if (!angleAxisModel) {
          throw new Error('angleAxis option not found');
        }

        if (!radiusAxisModel) {
          throw new Error('radiusAxis option not found');
        }
      }

      result.coordSysDims = ['radius', 'angle'];
      axisMap.set('radius', radiusAxisModel);
      axisMap.set('angle', angleAxisModel);

      if (isCategory(radiusAxisModel)) {
        categoryAxisMap.set('radius', radiusAxisModel);
        result.firstCategoryDimIndex = 0;
      }

      if (isCategory(angleAxisModel)) {
        categoryAxisMap.set('angle', angleAxisModel);
        result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1);
      }
    },
    geo: function (seriesModel, result, axisMap, categoryAxisMap) {
      result.coordSysDims = ['lng', 'lat'];
    },
    parallel: function (seriesModel, result, axisMap, categoryAxisMap) {
      var ecModel = seriesModel.ecModel;
      var parallelModel = ecModel.getComponent('parallel', seriesModel.get('parallelIndex'));
      var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();
      each(parallelModel.parallelAxisIndex, function (axisIndex, index) {
        var axisModel = ecModel.getComponent('parallelAxis', axisIndex);
        var axisDim = coordSysDims[index];
        axisMap.set(axisDim, axisModel);

        if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {
          categoryAxisMap.set(axisDim, axisModel);
          result.firstCategoryDimIndex = index;
        }
      });
    }
  };

  function isCategory(axisModel) {
    return axisModel.get('type') === 'category';
  }

  function enableDataStack(seriesModel, dimensionInfoList, opt) {
    opt = opt || {};
    var byIndex = opt.byIndex;
    var stackedCoordDimension = opt.stackedCoordDimension;
    var mayStack = !!(seriesModel && seriesModel.get('stack'));
    var stackedByDimInfo;
    var stackedDimInfo;
    var stackResultDimension;
    var stackedOverDimension;
    each(dimensionInfoList, function (dimensionInfo, index) {
      if (isString(dimensionInfo)) {
        dimensionInfoList[index] = dimensionInfo = {
          name: dimensionInfo
        };
      }

      if (mayStack && !dimensionInfo.isExtraCoord) {
        if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) {
          stackedByDimInfo = dimensionInfo;
        }

        if (!stackedDimInfo && dimensionInfo.type !== 'ordinal' && dimensionInfo.type !== 'time' && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)) {
          stackedDimInfo = dimensionInfo;
        }
      }
    });

    if (stackedDimInfo && !byIndex && !stackedByDimInfo) {
      byIndex = true;
    }

    if (stackedDimInfo) {
      stackResultDimension = '__\0ecstackresult';
      stackedOverDimension = '__\0ecstackedover';

      if (stackedByDimInfo) {
        stackedByDimInfo.createInvertedIndices = true;
      }

      var stackedDimCoordDim_1 = stackedDimInfo.coordDim;
      var stackedDimType = stackedDimInfo.type;
      var stackedDimCoordIndex_1 = 0;
      each(dimensionInfoList, function (dimensionInfo) {
        if (dimensionInfo.coordDim === stackedDimCoordDim_1) {
          stackedDimCoordIndex_1++;
        }
      });
      dimensionInfoList.push({
        name: stackResultDimension,
        coordDim: stackedDimCoordDim_1,
        coordDimIndex: stackedDimCoordIndex_1,
        type: stackedDimType,
        isExtraCoord: true,
        isCalculationCoord: true
      });
      stackedDimCoordIndex_1++;
      dimensionInfoList.push({
        name: stackedOverDimension,
        coordDim: stackedOverDimension,
        coordDimIndex: stackedDimCoordIndex_1,
        type: stackedDimType,
        isExtraCoord: true,
        isCalculationCoord: true
      });
    }

    return {
      stackedDimension: stackedDimInfo && stackedDimInfo.name,
      stackedByDimension: stackedByDimInfo && stackedByDimInfo.name,
      isStackedByIndex: byIndex,
      stackedOverDimension: stackedOverDimension,
      stackResultDimension: stackResultDimension
    };
  }

  function isDimensionStacked(data, stackedDim) {
    return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension');
  }

  function getStackedDimension(data, targetDim) {
    return isDimensionStacked(data, targetDim) ? data.getCalculationInfo('stackResultDimension') : targetDim;
  }

  function createListFromArray(source, seriesModel, opt) {
    opt = opt || {};

    if (!(source instanceof Source)) {
      source = Source.seriesDataToSource(source);
    }

    var coordSysName = seriesModel.get('coordinateSystem');
    var registeredCoordSys = CoordinateSystemManager.get(coordSysName);
    var coordSysInfo = getCoordSysInfoBySeries(seriesModel);
    var coordSysDimDefs;

    if (coordSysInfo && coordSysInfo.coordSysDims) {
      coordSysDimDefs = map(coordSysInfo.coordSysDims, function (dim) {
        var dimInfo = {
          name: dim
        };
        var axisModel = coordSysInfo.axisMap.get(dim);

        if (axisModel) {
          var axisType = axisModel.get('type');
          dimInfo.type = getDimensionTypeByAxis(axisType);
        }

        return dimInfo;
      });
    }

    if (!coordSysDimDefs) {
      coordSysDimDefs = registeredCoordSys && (registeredCoordSys.getDimensionsInfo ? registeredCoordSys.getDimensionsInfo() : registeredCoordSys.dimensions.slice()) || ['x', 'y'];
    }

    var useEncodeDefaulter = opt.useEncodeDefaulter;
    var dimInfoList = createDimensions(source, {
      coordDimensions: coordSysDimDefs,
      generateCoord: opt.generateCoord,
      encodeDefaulter: isFunction(useEncodeDefaulter) ? useEncodeDefaulter : useEncodeDefaulter ? curry(makeSeriesEncodeForAxisCoordSys, coordSysDimDefs, seriesModel) : null
    });
    var firstCategoryDimIndex;
    var hasNameEncode;
    coordSysInfo && each(dimInfoList, function (dimInfo, dimIndex) {
      var coordDim = dimInfo.coordDim;
      var categoryAxisModel = coordSysInfo.categoryAxisMap.get(coordDim);

      if (categoryAxisModel) {
        if (firstCategoryDimIndex == null) {
          firstCategoryDimIndex = dimIndex;
        }

        dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta();
      }

      if (dimInfo.otherDims.itemName != null) {
        hasNameEncode = true;
      }
    });

    if (!hasNameEncode && firstCategoryDimIndex != null) {
      dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0;
    }

    var stackCalculationInfo = enableDataStack(seriesModel, dimInfoList);
    var list = new List(dimInfoList, seriesModel);
    list.setCalculationInfo(stackCalculationInfo);
    var dimValueGetter = firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source) ? function (itemOpt, dimName, dataIndex, dimIndex) {
      return dimIndex === firstCategoryDimIndex ? dataIndex : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex);
    } : null;
    list.hasItemOption = false;
    list.initData(source, null, dimValueGetter);
    return list;
  }

  function isNeedCompleteOrdinalData(source) {
    if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) {
      var sampleItem = firstDataNotNull(source.data || []);
      return sampleItem != null && !isArray(getDataItemValue(sampleItem));
    }
  }

  function firstDataNotNull(data) {
    var i = 0;

    while (i < data.length && data[i] == null) {
      i++;
    }

    return data[i];
  }

  var LineSeriesModel = function (_super) {
    __extends(LineSeriesModel, _super);

    function LineSeriesModel() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = LineSeriesModel.type;
      _this.hasSymbolVisual = true;
      _this.legendSymbol = 'line';
      return _this;
    }

    LineSeriesModel.prototype.getInitialData = function (option) {
      if (true) {
        var coordSys = option.coordinateSystem;

        if (coordSys !== 'polar' && coordSys !== 'cartesian2d') {
          throw new Error('Line not support coordinateSystem besides cartesian and polar');
        }
      }

      return createListFromArray(this.getSource(), this, {
        useEncodeDefaulter: true
      });
    };

    LineSeriesModel.type = 'series.line';
    LineSeriesModel.dependencies = ['grid', 'polar'];
    LineSeriesModel.defaultOption = {
      zlevel: 0,
      z: 2,
      coordinateSystem: 'cartesian2d',
      legendHoverLink: true,
      clip: true,
      label: {
        position: 'top'
      },
      lineStyle: {
        width: 2,
        type: 'solid'
      },
      emphasis: {
        scale: true,
        lineStyle: {
          width: 'bolder'
        }
      },
      step: false,
      smooth: false,
      smoothMonotone: null,
      symbol: 'emptyCircle',
      symbolSize: 4,
      symbolRotate: null,
      showSymbol: true,
      showAllSymbol: 'auto',
      connectNulls: false,
      sampling: 'none',
      animationEasing: 'linear',
      progressive: 0,
      hoverLayerThreshold: Infinity
    };
    return LineSeriesModel;
  }(SeriesModel);

  SeriesModel.registerClass(LineSeriesModel);
  var Triangle = Path.extend({
    type: 'triangle',
    shape: {
      cx: 0,
      cy: 0,
      width: 0,
      height: 0
    },
    buildPath: function (path, shape) {
      var cx = shape.cx;
      var cy = shape.cy;
      var width = shape.width / 2;
      var height = shape.height / 2;
      path.moveTo(cx, cy - height);
      path.lineTo(cx + width, cy + height);
      path.lineTo(cx - width, cy + height);
      path.closePath();
    }
  });
  var Diamond = Path.extend({
    type: 'diamond',
    shape: {
      cx: 0,
      cy: 0,
      width: 0,
      height: 0
    },
    buildPath: function (path, shape) {
      var cx = shape.cx;
      var cy = shape.cy;
      var width = shape.width / 2;
      var height = shape.height / 2;
      path.moveTo(cx, cy - height);
      path.lineTo(cx + width, cy);
      path.lineTo(cx, cy + height);
      path.lineTo(cx - width, cy);
      path.closePath();
    }
  });
  var Pin = Path.extend({
    type: 'pin',
    shape: {
      x: 0,
      y: 0,
      width: 0,
      height: 0
    },
    buildPath: function (path, shape) {
      var x = shape.x;
      var y = shape.y;
      var w = shape.width / 5 * 3;
      var h = Math.max(w, shape.height);
      var r = w / 2;
      var dy = r * r / (h - r);
      var cy = y - h + r + dy;
      var angle = Math.asin(dy / r);
      var dx = Math.cos(angle) * r;
      var tanX = Math.sin(angle);
      var tanY = Math.cos(angle);
      var cpLen = r * 0.6;
      var cpLen2 = r * 0.7;
      path.moveTo(x - dx, cy + dy);
      path.arc(x, cy, r, Math.PI - angle, Math.PI * 2 + angle);
      path.bezierCurveTo(x + dx - tanX * cpLen, cy + dy + tanY * cpLen, x, y - cpLen2, x, y);
      path.bezierCurveTo(x, y - cpLen2, x - dx + tanX * cpLen, cy + dy + tanY * cpLen, x - dx, cy + dy);
      path.closePath();
    }
  });
  var Arrow = Path.extend({
    type: 'arrow',
    shape: {
      x: 0,
      y: 0,
      width: 0,
      height: 0
    },
    buildPath: function (ctx, shape) {
      var height = shape.height;
      var width = shape.width;
      var x = shape.x;
      var y = shape.y;
      var dx = width / 3 * 2;
      ctx.moveTo(x, y);
      ctx.lineTo(x + dx, y + height);
      ctx.lineTo(x, y + height / 4 * 3);
      ctx.lineTo(x - dx, y + height);
      ctx.lineTo(x, y);
      ctx.closePath();
    }
  });
  var symbolCtors = {
    line: Rect,
    rect: Rect,
    roundRect: Rect,
    square: Rect,
    circle: Circle,
    diamond: Diamond,
    pin: Pin,
    arrow: Arrow,
    triangle: Triangle
  };
  var symbolShapeMakers = {
    line: function (x, y, w, h, shape) {
      var thickness = 2;
      shape.x = x;
      shape.y = y + h / 2 - thickness / 2;
      shape.width = w;
      shape.height = thickness;
    },
    rect: function (x, y, w, h, shape) {
      shape.x = x;
      shape.y = y;
      shape.width = w;
      shape.height = h;
    },
    roundRect: function (x, y, w, h, shape) {
      shape.x = x;
      shape.y = y;
      shape.width = w;
      shape.height = h;
      shape.r = Math.min(w, h) / 4;
    },
    square: function (x, y, w, h, shape) {
      var size = Math.min(w, h);
      shape.x = x;
      shape.y = y;
      shape.width = size;
      shape.height = size;
    },
    circle: function (x, y, w, h, shape) {
      shape.cx = x + w / 2;
      shape.cy = y + h / 2;
      shape.r = Math.min(w, h) / 2;
    },
    diamond: function (x, y, w, h, shape) {
      shape.cx = x + w / 2;
      shape.cy = y + h / 2;
      shape.width = w;
      shape.height = h;
    },
    pin: function (x, y, w, h, shape) {
      shape.x = x + w / 2;
      shape.y = y + h / 2;
      shape.width = w;
      shape.height = h;
    },
    arrow: function (x, y, w, h, shape) {
      shape.x = x + w / 2;
      shape.y = y + h / 2;
      shape.width = w;
      shape.height = h;
    },
    triangle: function (x, y, w, h, shape) {
      shape.cx = x + w / 2;
      shape.cy = y + h / 2;
      shape.width = w;
      shape.height = h;
    }
  };
  var symbolBuildProxies = {};
  each(symbolCtors, function (Ctor, name) {
    symbolBuildProxies[name] = new Ctor();
  });
  var SymbolClz = Path.extend({
    type: 'symbol',
    shape: {
      symbolType: '',
      x: 0,
      y: 0,
      width: 0,
      height: 0
    },
    calculateTextPosition: function (out, config, rect) {
      var res = calculateTextPosition(out, config, rect);
      var shape = this.shape;

      if (shape && shape.symbolType === 'pin' && config.position === 'inside') {
        res.y = rect.y + rect.height * 0.4;
      }

      return res;
    },
    buildPath: function (ctx, shape, inBundle) {
      var symbolType = shape.symbolType;

      if (symbolType !== 'none') {
        var proxySymbol = symbolBuildProxies[symbolType];

        if (!proxySymbol) {
          symbolType = 'rect';
          proxySymbol = symbolBuildProxies[symbolType];
        }

        symbolShapeMakers[symbolType](shape.x, shape.y, shape.width, shape.height, proxySymbol.shape);
        proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);
      }
    }
  });

  function symbolPathSetColor(color, innerColor) {
    if (this.type !== 'image') {
      var symbolStyle = this.style;

      if (this.__isEmptyBrush) {
        symbolStyle.stroke = color;
        symbolStyle.fill = innerColor || '#fff';
        symbolStyle.lineWidth = 2;
      } else {
        symbolStyle.fill = color;
      }

      this.markRedraw();
    }
  }

  function createSymbol(symbolType, x, y, w, h, color, keepAspect) {
    var isEmpty = symbolType.indexOf('empty') === 0;

    if (isEmpty) {
      symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);
    }

    var symbolPath;

    if (symbolType.indexOf('image://') === 0) {
      symbolPath = makeImage(symbolType.slice(8), new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover');
    } else if (symbolType.indexOf('path://') === 0) {
      symbolPath = makePath(symbolType.slice(7), {}, new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover');
    } else {
      symbolPath = new SymbolClz({
        shape: {
          symbolType: symbolType,
          x: x,
          y: y,
          width: w,
          height: h
        }
      });
    }

    symbolPath.__isEmptyBrush = isEmpty;
    symbolPath.setColor = symbolPathSetColor;

    if (color) {
      symbolPath.setColor(color);
    }

    return symbolPath;
  }

  function getDefaultLabel(data, dataIndex, interpolatedValues) {
    var labelDims = data.mapDimensionsAll('defaultedLabel');
    var len = labelDims.length;

    if (len === 1) {
      return interpolatedValues == null ? retrieveRawValue(data, dataIndex, labelDims[0]) : interpolatedValues;
    } else if (len) {
      var vals = [];

      for (var i = 0; i < labelDims.length; i++) {
        var val = interpolatedValues == null ? retrieveRawValue(data, dataIndex, labelDims[i]) : interpolatedValues;
        vals.push(val);
      }

      return vals.join(' ');
    }
  }

  var Symbol = function (_super) {
    __extends(Symbol, _super);

    function Symbol(data, idx, seriesScope, opts) {
      var _this = _super.call(this) || this;

      _this.updateData(data, idx, seriesScope, opts);

      return _this;
    }

    Symbol.prototype._createSymbol = function (symbolType, data, idx, symbolSize, keepAspect) {
      this.removeAll();
      var symbolPath = createSymbol(symbolType, -1, -1, 2, 2, null, keepAspect);
      symbolPath.attr({
        z2: 100,
        culling: true,
        scaleX: symbolSize[0] / 2,
        scaleY: symbolSize[1] / 2
      });
      symbolPath.drift = driftSymbol;
      this._symbolType = symbolType;
      this.add(symbolPath);
    };

    Symbol.prototype.stopSymbolAnimation = function (toLastFrame) {
      this.childAt(0).stopAnimation(null, toLastFrame);
    };

    Symbol.prototype.getSymbolPath = function () {
      return this.childAt(0);
    };

    Symbol.prototype.highlight = function () {
      enterEmphasis(this.childAt(0));
    };

    Symbol.prototype.downplay = function () {
      leaveEmphasis(this.childAt(0));
    };

    Symbol.prototype.setZ = function (zlevel, z) {
      var symbolPath = this.childAt(0);
      symbolPath.zlevel = zlevel;
      symbolPath.z = z;
    };

    Symbol.prototype.setDraggable = function (draggable) {
      var symbolPath = this.childAt(0);
      symbolPath.draggable = draggable;
      symbolPath.cursor = draggable ? 'move' : symbolPath.cursor;
    };

    Symbol.prototype.updateData = function (data, idx, seriesScope, opts) {
      this.silent = false;
      var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';
      var seriesModel = data.hostModel;
      var symbolSize = Symbol.getSymbolSize(data, idx);
      var isInit = symbolType !== this._symbolType;

      if (isInit) {
        var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect');

        this._createSymbol(symbolType, data, idx, symbolSize, keepAspect);
      } else {
        var symbolPath = this.childAt(0);
        symbolPath.silent = false;
        updateProps(symbolPath, {
          scaleX: symbolSize[0] / 2,
          scaleY: symbolSize[1] / 2
        }, seriesModel, idx);
      }

      this._updateCommon(data, idx, symbolSize, seriesScope, opts);

      if (isInit) {
        var symbolPath = this.childAt(0);
        var target = {
          scaleX: this._sizeX,
          scaleY: this._sizeY,
          style: {
            opacity: symbolPath.style.opacity
          }
        };
        symbolPath.scaleX = symbolPath.scaleY = 0;
        symbolPath.style.opacity = 0;
        initProps(symbolPath, target, seriesModel, idx);
      }

      this._seriesModel = seriesModel;
    };

    Symbol.prototype._updateCommon = function (data, idx, symbolSize, seriesScope, opts) {
      var symbolPath = this.childAt(0);
      var seriesModel = data.hostModel;
      var emphasisItemStyle;
      var blurItemStyle;
      var selectItemStyle;
      var focus;
      var blurScope;
      var symbolOffset;
      var labelStatesModels;
      var hoverScale;
      var cursorStyle;

      if (seriesScope) {
        emphasisItemStyle = seriesScope.emphasisItemStyle;
        blurItemStyle = seriesScope.blurItemStyle;
        selectItemStyle = seriesScope.selectItemStyle;
        focus = seriesScope.focus;
        blurScope = seriesScope.blurScope;
        symbolOffset = seriesScope.symbolOffset;
        labelStatesModels = seriesScope.labelStatesModels;
        hoverScale = seriesScope.hoverScale;
        cursorStyle = seriesScope.cursorStyle;
      }

      if (!seriesScope || data.hasItemOption) {
        var itemModel = seriesScope && seriesScope.itemModel ? seriesScope.itemModel : data.getItemModel(idx);
        var emphasisModel = itemModel.getModel('emphasis');
        emphasisItemStyle = emphasisModel.getModel('itemStyle').getItemStyle();
        selectItemStyle = itemModel.getModel(['select', 'itemStyle']).getItemStyle();
        blurItemStyle = itemModel.getModel(['blur', 'itemStyle']).getItemStyle();
        focus = emphasisModel.get('focus');
        blurScope = emphasisModel.get('blurScope');
        symbolOffset = itemModel.getShallow('symbolOffset');
        labelStatesModels = getLabelStatesModels(itemModel);
        hoverScale = emphasisModel.getShallow('scale');
        cursorStyle = itemModel.getShallow('cursor');
      }

      var symbolRotate = data.getItemVisual(idx, 'symbolRotate');
      symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0);

      if (symbolOffset) {
        symbolPath.x = parsePercent$2(symbolOffset[0], symbolSize[0]);
        symbolPath.y = parsePercent$2(symbolOffset[1], symbolSize[1]);
      }

      cursorStyle && symbolPath.attr('cursor', cursorStyle);
      var symbolStyle = data.getItemVisual(idx, 'style');
      var visualColor = symbolStyle.fill;

      if (symbolPath instanceof ZRImage) {
        var pathStyle = symbolPath.style;
        symbolPath.useStyle(extend({
          image: pathStyle.image,
          x: pathStyle.x,
          y: pathStyle.y,
          width: pathStyle.width,
          height: pathStyle.height
        }, symbolStyle));
      } else {
        if (symbolPath.__isEmptyBrush) {
          symbolPath.useStyle(extend({}, symbolStyle));
        } else {
          symbolPath.useStyle(symbolStyle);
        }

        symbolPath.setColor(visualColor, opts && opts.symbolInnerColor);
        symbolPath.style.strokeNoScale = true;
      }

      var liftZ = data.getItemVisual(idx, 'liftZ');
      var z2Origin = this._z2;

      if (liftZ != null) {
        if (z2Origin == null) {
          this._z2 = symbolPath.z2;
          symbolPath.z2 += liftZ;
        }
      } else if (z2Origin != null) {
        symbolPath.z2 = z2Origin;
        this._z2 = null;
      }

      var useNameLabel = opts && opts.useNameLabel;
      setLabelStyle(symbolPath, labelStatesModels, {
        labelFetcher: seriesModel,
        labelDataIndex: idx,
        defaultText: getLabelDefaultText,
        inheritColor: visualColor
      });

      function getLabelDefaultText(idx) {
        return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx);
      }

      this._sizeX = symbolSize[0] / 2;
      this._sizeY = symbolSize[1] / 2;
      symbolPath.ensureState('emphasis').style = emphasisItemStyle;
      symbolPath.ensureState('select').style = selectItemStyle;
      symbolPath.ensureState('blur').style = blurItemStyle;

      if (hoverScale) {
        this.ensureState('emphasis');
        this.setSymbolScale(1);
      } else {
        this.states.emphasis = null;
      }

      enableHoverEmphasis(this, focus, blurScope);
    };

    Symbol.prototype.setSymbolScale = function (scale) {
      var emphasisState = this.states.emphasis;

      if (emphasisState) {
        var hoverScale = Math.max(scale * 1.1, 3 / this._sizeY + scale);
        emphasisState.scaleX = hoverScale;
        emphasisState.scaleY = hoverScale;
      }

      this.scaleX = this.scaleY = scale;
    };

    Symbol.prototype.fadeOut = function (cb, opt) {
      var symbolPath = this.childAt(0);
      this.silent = symbolPath.silent = true;
      !(opt && opt.keepLabel) && symbolPath.removeTextContent();
      removeElement(symbolPath, {
        style: {
          opacity: 0
        },
        scaleX: 0,
        scaleY: 0
      }, this._seriesModel, getECData(this).dataIndex, cb);
    };

    Symbol.getSymbolSize = function (data, idx) {
      var symbolSize = data.getItemVisual(idx, 'symbolSize');
      return symbolSize instanceof Array ? symbolSize.slice() : [+symbolSize, +symbolSize];
    };

    return Symbol;
  }(Group);

  function driftSymbol(dx, dy) {
    this.parent.drift(dx, dy);
  }

  function symbolNeedsDraw(data, point, idx, opt) {
    return point && !isNaN(point[0]) && !isNaN(point[1]) && !(opt.isIgnore && opt.isIgnore(idx)) && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1])) && data.getItemVisual(idx, 'symbol') !== 'none';
  }

  function normalizeUpdateOpt(opt) {
    if (opt != null && !isObject(opt)) {
      opt = {
        isIgnore: opt
      };
    }

    return opt || {};
  }

  function makeSeriesScope(data) {
    var seriesModel = data.hostModel;
    var emphasisModel = seriesModel.getModel('emphasis');
    return {
      emphasisItemStyle: emphasisModel.getModel('itemStyle').getItemStyle(),
      blurItemStyle: seriesModel.getModel(['blur', 'itemStyle']).getItemStyle(),
      selectItemStyle: seriesModel.getModel(['select', 'itemStyle']).getItemStyle(),
      focus: emphasisModel.get('focus'),
      blurScope: emphasisModel.get('blurScope'),
      symbolRotate: seriesModel.get('symbolRotate'),
      symbolOffset: seriesModel.get('symbolOffset'),
      hoverScale: emphasisModel.get('scale'),
      labelStatesModels: getLabelStatesModels(seriesModel),
      cursorStyle: seriesModel.get('cursor')
    };
  }

  var SymbolDraw = function () {
    function SymbolDraw(SymbolCtor) {
      this.group = new Group();
      this._SymbolCtor = SymbolCtor || Symbol;
    }

    SymbolDraw.prototype.updateData = function (data, opt) {
      opt = normalizeUpdateOpt(opt);
      var group = this.group;
      var seriesModel = data.hostModel;
      var oldData = this._data;
      var SymbolCtor = this._SymbolCtor;
      var seriesScope = makeSeriesScope(data);

      if (!oldData) {
        group.removeAll();
      }

      data.diff(oldData).add(function (newIdx) {
        var point = data.getItemLayout(newIdx);

        if (symbolNeedsDraw(data, point, newIdx, opt)) {
          var symbolEl = new SymbolCtor(data, newIdx, seriesScope);
          symbolEl.setPosition(point);
          data.setItemGraphicEl(newIdx, symbolEl);
          group.add(symbolEl);
        }
      }).update(function (newIdx, oldIdx) {
        var symbolEl = oldData.getItemGraphicEl(oldIdx);
        var point = data.getItemLayout(newIdx);

        if (!symbolNeedsDraw(data, point, newIdx, opt)) {
          group.remove(symbolEl);
          return;
        }

        if (!symbolEl) {
          symbolEl = new SymbolCtor(data, newIdx);
          symbolEl.setPosition(point);
        } else {
          symbolEl.updateData(data, newIdx, seriesScope);
          updateProps(symbolEl, {
            x: point[0],
            y: point[1]
          }, seriesModel);
        }

        group.add(symbolEl);
        data.setItemGraphicEl(newIdx, symbolEl);
      }).remove(function (oldIdx) {
        var el = oldData.getItemGraphicEl(oldIdx);
        el && el.fadeOut(function () {
          group.remove(el);
        });
      }).execute();
      this._data = data;
    };

    SymbolDraw.prototype.isPersistent = function () {
      return true;
    };

    SymbolDraw.prototype.updateLayout = function () {
      var data = this._data;

      if (data) {
        data.eachItemGraphicEl(function (el, idx) {
          var point = data.getItemLayout(idx);
          el.setPosition(point);
          el.markRedraw();
        });
      }
    };

    SymbolDraw.prototype.incrementalPrepareUpdate = function (data) {
      this._seriesScope = makeSeriesScope(data);
      this._data = null;
      this.group.removeAll();
    };

    SymbolDraw.prototype.incrementalUpdate = function (taskParams, data, opt) {
      opt = normalizeUpdateOpt(opt);

      function updateIncrementalAndHover(el) {
        if (!el.isGroup) {
          el.incremental = true;
          el.ensureState('emphasis').hoverLayer = true;
        }
      }

      for (var idx = taskParams.start; idx < taskParams.end; idx++) {
        var point = data.getItemLayout(idx);

        if (symbolNeedsDraw(data, point, idx, opt)) {
          var el = new this._SymbolCtor(data, idx, this._seriesScope);
          el.traverse(updateIncrementalAndHover);
          el.setPosition(point);
          this.group.add(el);
          data.setItemGraphicEl(idx, el);
        }
      }
    };

    SymbolDraw.prototype.remove = function (enableAnimation) {
      var group = this.group;
      var data = this._data;

      if (data && enableAnimation) {
        data.eachItemGraphicEl(function (el) {
          el.fadeOut(function () {
            group.remove(el);
          });
        });
      } else {
        group.removeAll();
      }
    };

    return SymbolDraw;
  }();

  function prepareDataCoordInfo(coordSys, data, valueOrigin) {
    var baseAxis = coordSys.getBaseAxis();
    var valueAxis = coordSys.getOtherAxis(baseAxis);
    var valueStart = getValueStart(valueAxis, valueOrigin);
    var baseAxisDim = baseAxis.dim;
    var valueAxisDim = valueAxis.dim;
    var valueDim = data.mapDimension(valueAxisDim);
    var baseDim = data.mapDimension(baseAxisDim);
    var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0;
    var dims = map(coordSys.dimensions, function (coordDim) {
      return data.mapDimension(coordDim);
    });
    var stacked = false;
    var stackResultDim = data.getCalculationInfo('stackResultDimension');

    if (isDimensionStacked(data, dims[0])) {
      stacked = true;
      dims[0] = stackResultDim;
    }

    if (isDimensionStacked(data, dims[1])) {
      stacked = true;
      dims[1] = stackResultDim;
    }

    return {
      dataDimsForPoint: dims,
      valueStart: valueStart,
      valueAxisDim: valueAxisDim,
      baseAxisDim: baseAxisDim,
      stacked: !!stacked,
      valueDim: valueDim,
      baseDim: baseDim,
      baseDataOffset: baseDataOffset,
      stackedOverDimension: data.getCalculationInfo('stackedOverDimension')
    };
  }

  function getValueStart(valueAxis, valueOrigin) {
    var valueStart = 0;
    var extent = valueAxis.scale.getExtent();

    if (valueOrigin === 'start') {
      valueStart = extent[0];
    } else if (valueOrigin === 'end') {
      valueStart = extent[1];
    } else {
      if (extent[0] > 0) {
        valueStart = extent[0];
      } else if (extent[1] < 0) {
        valueStart = extent[1];
      }
    }

    return valueStart;
  }

  function getStackedOnPoint(dataCoordInfo, coordSys, data, idx) {
    var value = NaN;

    if (dataCoordInfo.stacked) {
      value = data.get(data.getCalculationInfo('stackedOverDimension'), idx);
    }

    if (isNaN(value)) {
      value = dataCoordInfo.valueStart;
    }

    var baseDataOffset = dataCoordInfo.baseDataOffset;
    var stackedData = [];
    stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx);
    stackedData[1 - baseDataOffset] = value;
    return coordSys.dataToPoint(stackedData);
  }

  function diffData(oldData, newData) {
    var diffResult = [];
    newData.diff(oldData).add(function (idx) {
      diffResult.push({
        cmd: '+',
        idx: idx
      });
    }).update(function (newIdx, oldIdx) {
      diffResult.push({
        cmd: '=',
        idx: oldIdx,
        idx1: newIdx
      });
    }).remove(function (idx) {
      diffResult.push({
        cmd: '-',
        idx: idx
      });
    }).execute();
    return diffResult;
  }

  function lineAnimationDiff(oldData, newData, oldStackedOnPoints, newStackedOnPoints, oldCoordSys, newCoordSys, oldValueOrigin, newValueOrigin) {
    var diff = diffData(oldData, newData);
    var currPoints = [];
    var nextPoints = [];
    var currStackedPoints = [];
    var nextStackedPoints = [];
    var status = [];
    var sortedIndices = [];
    var rawIndices = [];
    var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin);
    var oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin);

    for (var i = 0; i < diff.length; i++) {
      var diffItem = diff[i];
      var pointAdded = true;

      switch (diffItem.cmd) {
        case '=':
          var currentPt = oldData.getItemLayout(diffItem.idx);
          var nextPt = newData.getItemLayout(diffItem.idx1);

          if (isNaN(currentPt[0]) || isNaN(currentPt[1])) {
            currentPt = nextPt.slice();
          }

          currPoints.push(currentPt);
          nextPoints.push(nextPt);
          currStackedPoints.push(oldStackedOnPoints[diffItem.idx]);
          nextStackedPoints.push(newStackedOnPoints[diffItem.idx1]);
          rawIndices.push(newData.getRawIndex(diffItem.idx1));
          break;

        case '+':
          var idxAdd = diffItem.idx;
          currPoints.push(oldCoordSys.dataToPoint([newData.get(newDataOldCoordInfo.dataDimsForPoint[0], idxAdd), newData.get(newDataOldCoordInfo.dataDimsForPoint[1], idxAdd)]));
          nextPoints.push(newData.getItemLayout(idxAdd).slice());
          currStackedPoints.push(getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, idxAdd));
          nextStackedPoints.push(newStackedOnPoints[idxAdd]);
          rawIndices.push(newData.getRawIndex(idxAdd));
          break;

        case '-':
          var idxMinus = diffItem.idx;
          var rawIndex = oldData.getRawIndex(idxMinus);

          if (rawIndex !== idxMinus) {
            currPoints.push(oldData.getItemLayout(idxMinus));
            nextPoints.push(newCoordSys.dataToPoint([oldData.get(oldDataNewCoordInfo.dataDimsForPoint[0], idxMinus), oldData.get(oldDataNewCoordInfo.dataDimsForPoint[1], idxMinus)]));
            currStackedPoints.push(oldStackedOnPoints[idxMinus]);
            nextStackedPoints.push(getStackedOnPoint(oldDataNewCoordInfo, newCoordSys, oldData, idxMinus));
            rawIndices.push(rawIndex);
          } else {
            pointAdded = false;
          }

      }

      if (pointAdded) {
        status.push(diffItem);
        sortedIndices.push(sortedIndices.length);
      }
    }

    sortedIndices.sort(function (a, b) {
      return rawIndices[a] - rawIndices[b];
    });
    var sortedCurrPoints = [];
    var sortedNextPoints = [];
    var sortedCurrStackedPoints = [];
    var sortedNextStackedPoints = [];
    var sortedStatus = [];

    for (var i = 0; i < sortedIndices.length; i++) {
      var idx = sortedIndices[i];
      sortedCurrPoints[i] = currPoints[idx];
      sortedNextPoints[i] = nextPoints[idx];
      sortedCurrStackedPoints[i] = currStackedPoints[idx];
      sortedNextStackedPoints[i] = nextStackedPoints[idx];
      sortedStatus[i] = status[idx];
    }

    return {
      current: sortedCurrPoints,
      next: sortedNextPoints,
      stackedOnCurrent: sortedCurrStackedPoints,
      stackedOnNext: sortedNextStackedPoints,
      status: sortedStatus
    };
  }

  var vec2Min = min;
  var vec2Max = max;
  var scaleAndAdd$1 = scaleAndAdd;
  var v2Copy = copy;
  var v = [];
  var cp0 = [];
  var cp1 = [];

  function isPointNull(p) {
    return isNaN(p[0]) || isNaN(p[1]);
  }

  function drawSegment(ctx, points, start, segLen, allLen, dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls) {
    return (smoothMonotone === 'none' || !smoothMonotone ? drawNonMono : drawMono)(ctx, points, start, segLen, allLen, dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls);
  }

  function drawMono(ctx, points, start, segLen, allLen, dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls) {
    var prevIdx = 0;
    var idx = start;
    var k = 0;

    for (; k < segLen; k++) {
      var p = points[idx];

      if (idx >= allLen || idx < 0) {
        break;
      }

      if (isPointNull(p)) {
        if (connectNulls) {
          idx += dir;
          continue;
        }

        break;
      }

      if (idx === start) {
        ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);
      } else {
        if (smooth > 0) {
          var prevP = points[prevIdx];
          var dim = smoothMonotone === 'y' ? 1 : 0;
          var ctrlLen = (p[dim] - prevP[dim]) * smooth;
          v2Copy(cp0, prevP);
          cp0[dim] = prevP[dim] + ctrlLen;
          v2Copy(cp1, p);
          cp1[dim] = p[dim] - ctrlLen;
          ctx.bezierCurveTo(cp0[0], cp0[1], cp1[0], cp1[1], p[0], p[1]);
        } else {
          ctx.lineTo(p[0], p[1]);
        }
      }

      prevIdx = idx;
      idx += dir;
    }

    return k;
  }

  function drawNonMono(ctx, points, start, segLen, allLen, dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls) {
    var prevIdx = 0;
    var idx = start;
    var k = 0;

    for (; k < segLen; k++) {
      var p = points[idx];

      if (idx >= allLen || idx < 0) {
        break;
      }

      if (isPointNull(p)) {
        if (connectNulls) {
          idx += dir;
          continue;
        }

        break;
      }

      if (idx === start) {
        ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);
        v2Copy(cp0, p);
      } else {
        if (smooth > 0) {
          var nextIdx = idx + dir;
          var nextP = points[nextIdx];

          if (connectNulls) {
            while (nextP && isPointNull(points[nextIdx])) {
              nextIdx += dir;
              nextP = points[nextIdx];
            }
          }

          var ratioNextSeg = 0.5;
          var prevP = points[prevIdx];
          nextP = points[nextIdx];

          if (!nextP || isPointNull(nextP)) {
            v2Copy(cp1, p);
          } else {
            if (isPointNull(nextP) && !connectNulls) {
              nextP = p;
            }

            sub(v, nextP, prevP);
            var lenPrevSeg = void 0;
            var lenNextSeg = void 0;

            if (smoothMonotone === 'x' || smoothMonotone === 'y') {
              var dim = smoothMonotone === 'x' ? 0 : 1;
              lenPrevSeg = Math.abs(p[dim] - prevP[dim]);
              lenNextSeg = Math.abs(p[dim] - nextP[dim]);
            } else {
              lenPrevSeg = dist(p, prevP);
              lenNextSeg = dist(p, nextP);
            }

            ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);
            scaleAndAdd$1(cp1, p, v, -smooth * (1 - ratioNextSeg));
          }

          vec2Min(cp0, cp0, smoothMax);
          vec2Max(cp0, cp0, smoothMin);
          vec2Min(cp1, cp1, smoothMax);
          vec2Max(cp1, cp1, smoothMin);
          ctx.bezierCurveTo(cp0[0], cp0[1], cp1[0], cp1[1], p[0], p[1]);
          scaleAndAdd$1(cp0, p, v, smooth * ratioNextSeg);
        } else {
          ctx.lineTo(p[0], p[1]);
        }
      }

      prevIdx = idx;
      idx += dir;
    }

    return k;
  }

  function getBoundingBox(points, smoothConstraint) {
    var ptMin = [Infinity, Infinity];
    var ptMax = [-Infinity, -Infinity];

    if (smoothConstraint) {
      for (var i = 0; i < points.length; i++) {
        var pt = points[i];

        if (pt[0] < ptMin[0]) {
          ptMin[0] = pt[0];
        }

        if (pt[1] < ptMin[1]) {
          ptMin[1] = pt[1];
        }

        if (pt[0] > ptMax[0]) {
          ptMax[0] = pt[0];
        }

        if (pt[1] > ptMax[1]) {
          ptMax[1] = pt[1];
        }
      }
    }

    return {
      min: smoothConstraint ? ptMin : ptMax,
      max: smoothConstraint ? ptMax : ptMin
    };
  }

  var ECPolylineShape = function () {
    function ECPolylineShape() {
      this.smooth = 0;
      this.smoothConstraint = true;
      this.connectNulls = false;
    }

    return ECPolylineShape;
  }();

  var ECPolyline = function (_super) {
    __extends(ECPolyline, _super);

    function ECPolyline(opts) {
      var _this = _super.call(this, opts) || this;

      _this.type = 'ec-polyline';
      return _this;
    }

    ECPolyline.prototype.getDefaultStyle = function () {
      return {
        stroke: '#000',
        fill: null
      };
    };

    ECPolyline.prototype.getDefaultShape = function () {
      return new ECPolylineShape();
    };

    ECPolyline.prototype.buildPath = function (ctx, shape) {
      var points = shape.points;
      var i = 0;
      var len = points.length;
      var result = getBoundingBox(points, shape.smoothConstraint);

      if (shape.connectNulls) {
        for (; len > 0; len--) {
          if (!isPointNull(points[len - 1])) {
            break;
          }
        }

        for (; i < len; i++) {
          if (!isPointNull(points[i])) {
            break;
          }
        }
      }

      while (i < len) {
        i += drawSegment(ctx, points, i, len, len, 1, result.min, result.max, shape.smooth, shape.smoothMonotone, shape.connectNulls) + 1;
      }
    };

    return ECPolyline;
  }(Path);

  var ECPolygonShape = function (_super) {
    __extends(ECPolygonShape, _super);

    function ECPolygonShape() {
      return _super !== null && _super.apply(this, arguments) || this;
    }

    return ECPolygonShape;
  }(ECPolylineShape);

  var ECPolygon = function (_super) {
    __extends(ECPolygon, _super);

    function ECPolygon(opts) {
      var _this = _super.call(this, opts) || this;

      _this.type = 'ec-polygon';
      return _this;
    }

    ECPolygon.prototype.getDefaultShape = function () {
      return new ECPolygonShape();
    };

    ECPolygon.prototype.buildPath = function (ctx, shape) {
      var points = shape.points;
      var stackedOnPoints = shape.stackedOnPoints;
      var i = 0;
      var len = points.length;
      var smoothMonotone = shape.smoothMonotone;
      var bbox = getBoundingBox(points, shape.smoothConstraint);
      var stackedOnBBox = getBoundingBox(stackedOnPoints, shape.smoothConstraint);

      if (shape.connectNulls) {
        for (; len > 0; len--) {
          if (!isPointNull(points[len - 1])) {
            break;
          }
        }

        for (; i < len; i++) {
          if (!isPointNull(points[i])) {
            break;
          }
        }
      }

      while (i < len) {
        var k = drawSegment(ctx, points, i, len, len, 1, bbox.min, bbox.max, shape.smooth, smoothMonotone, shape.connectNulls);
        drawSegment(ctx, stackedOnPoints, i + k - 1, k, len, -1, stackedOnBBox.min, stackedOnBBox.max, shape.stackedOnSmooth, smoothMonotone, shape.connectNulls);
        i += k + 1;
        ctx.closePath();
      }
    };

    return ECPolygon;
  }(Path);

  function createGridClipPath(cartesian, hasAnimation, seriesModel) {
    var rect = cartesian.getArea();
    var isHorizontal = cartesian.getBaseAxis().isHorizontal();
    var x = rect.x;
    var y = rect.y;
    var width = rect.width;
    var height = rect.height;
    var lineWidth = seriesModel.get(['lineStyle', 'width']) || 2;
    x -= lineWidth / 2;
    y -= lineWidth / 2;
    width += lineWidth;
    height += lineWidth;
    x = Math.floor(x);
    width = Math.round(width);
    var clipPath = new Rect({
      shape: {
        x: x,
        y: y,
        width: width,
        height: height
      }
    });

    if (hasAnimation) {
      clipPath.shape[isHorizontal ? 'width' : 'height'] = 0;
      initProps(clipPath, {
        shape: {
          width: width,
          height: height
        }
      }, seriesModel);
    }

    return clipPath;
  }

  function createPolarClipPath(polar, hasAnimation, seriesModel) {
    var sectorArea = polar.getArea();
    var clipPath = new Sector({
      shape: {
        cx: round$1(polar.cx, 1),
        cy: round$1(polar.cy, 1),
        r0: round$1(sectorArea.r0, 1),
        r: round$1(sectorArea.r, 1),
        startAngle: sectorArea.startAngle,
        endAngle: sectorArea.endAngle,
        clockwise: sectorArea.clockwise
      }
    });

    if (hasAnimation) {
      clipPath.shape.endAngle = sectorArea.startAngle;
      initProps(clipPath, {
        shape: {
          endAngle: sectorArea.endAngle
        }
      }, seriesModel);
    }

    return clipPath;
  }

  function createClipPath(coordSys, hasAnimation, seriesModel) {
    if (!coordSys) {
      return null;
    } else if (coordSys.type === 'polar') {
      return createPolarClipPath(coordSys, hasAnimation, seriesModel);
    } else if (coordSys.type === 'cartesian2d') {
      return createGridClipPath(coordSys, hasAnimation, seriesModel);
    }

    return null;
  }

  function isPointsSame(points1, points2) {
    if (points1.length !== points2.length) {
      return;
    }

    for (var i = 0; i < points1.length; i++) {
      var p1 = points1[i];
      var p2 = points2[i];

      if (p1[0] !== p2[0] || p1[1] !== p2[1]) {
        return;
      }
    }

    return true;
  }

  function getBoundingDiff(points1, points2) {
    var min1 = [];
    var max1 = [];
    var min2 = [];
    var max2 = [];
    fromPoints(points1, min1, max1);
    fromPoints(points2, min2, max2);
    return Math.max(Math.abs(min1[0] - min2[0]), Math.abs(min1[1] - min2[1]), Math.abs(max1[0] - max2[0]), Math.abs(max1[1] - max2[1]));
  }

  function getSmooth(smooth) {
    return typeof smooth === 'number' ? smooth : smooth ? 0.5 : 0;
  }

  function getStackedOnPoints(coordSys, data, dataCoordInfo) {
    if (!dataCoordInfo.valueDim) {
      return [];
    }

    var points = [];

    for (var idx = 0, len = data.count(); idx < len; idx++) {
      points.push(getStackedOnPoint(dataCoordInfo, coordSys, data, idx));
    }

    return points;
  }

  function turnPointsIntoStep(points, coordSys, stepTurnAt) {
    var baseAxis = coordSys.getBaseAxis();
    var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;
    var stepPoints = [];
    var i = 0;

    for (; i < points.length - 1; i++) {
      var nextPt = points[i + 1];
      var pt = points[i];
      stepPoints.push(pt);
      var stepPt = [];

      switch (stepTurnAt) {
        case 'end':
          stepPt[baseIndex] = nextPt[baseIndex];
          stepPt[1 - baseIndex] = pt[1 - baseIndex];
          stepPoints.push(stepPt);
          break;

        case 'middle':
          var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;
          var stepPt2 = [];
          stepPt[baseIndex] = stepPt2[baseIndex] = middle;
          stepPt[1 - baseIndex] = pt[1 - baseIndex];
          stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];
          stepPoints.push(stepPt);
          stepPoints.push(stepPt2);
          break;

        default:
          stepPt[baseIndex] = pt[baseIndex];
          stepPt[1 - baseIndex] = nextPt[1 - baseIndex];
          stepPoints.push(stepPt);
      }
    }

    points[i] && stepPoints.push(points[i]);
    return stepPoints;
  }

  function getVisualGradient(data, coordSys) {
    var visualMetaList = data.getVisual('visualMeta');

    if (!visualMetaList || !visualMetaList.length || !data.count()) {
      return;
    }

    if (coordSys.type !== 'cartesian2d') {
      if (true) {
        console.warn('Visual map on line style is only supported on cartesian2d.');
      }

      return;
    }

    var coordDim;
    var visualMeta;

    for (var i = visualMetaList.length - 1; i >= 0; i--) {
      var dimIndex = visualMetaList[i].dimension;
      var dimName = data.dimensions[dimIndex];
      var dimInfo = data.getDimensionInfo(dimName);
      coordDim = dimInfo && dimInfo.coordDim;

      if (coordDim === 'x' || coordDim === 'y') {
        visualMeta = visualMetaList[i];
        break;
      }
    }

    if (!visualMeta) {
      if (true) {
        console.warn('Visual map on line style only support x or y dimension.');
      }

      return;
    }

    var axis = coordSys.getAxis(coordDim);
    var colorStops = map(visualMeta.stops, function (stop) {
      return {
        offset: 0,
        coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),
        color: stop.color
      };
    });
    var stopLen = colorStops.length;
    var outerColors = visualMeta.outerColors.slice();

    if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {
      colorStops.reverse();
      outerColors.reverse();
    }

    var tinyExtent = 10;
    var minCoord = colorStops[0].coord - tinyExtent;
    var maxCoord = colorStops[stopLen - 1].coord + tinyExtent;
    var coordSpan = maxCoord - minCoord;

    if (coordSpan < 1e-3) {
      return 'transparent';
    }

    each(colorStops, function (stop) {
      stop.offset = (stop.coord - minCoord) / coordSpan;
    });
    colorStops.push({
      offset: stopLen ? colorStops[stopLen - 1].offset : 0.5,
      color: outerColors[1] || 'transparent'
    });
    colorStops.unshift({
      offset: stopLen ? colorStops[0].offset : 0.5,
      color: outerColors[0] || 'transparent'
    });
    var gradient = new LinearGradient(0, 0, 0, 0, colorStops, true);
    gradient[coordDim] = minCoord;
    gradient[coordDim + '2'] = maxCoord;
    return gradient;
  }

  function getIsIgnoreFunc(seriesModel, data, coordSys) {
    var showAllSymbol = seriesModel.get('showAllSymbol');
    var isAuto = showAllSymbol === 'auto';

    if (showAllSymbol && !isAuto) {
      return;
    }

    var categoryAxis = coordSys.getAxesByScale('ordinal')[0];

    if (!categoryAxis) {
      return;
    }

    if (isAuto && canShowAllSymbolForCategory(categoryAxis, data)) {
      return;
    }

    var categoryDataDim = data.mapDimension(categoryAxis.dim);
    var labelMap = {};
    each(categoryAxis.getViewLabels(), function (labelItem) {
      labelMap[labelItem.tickValue] = 1;
    });
    return function (dataIndex) {
      return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex));
    };
  }

  function canShowAllSymbolForCategory(categoryAxis, data) {
    var axisExtent = categoryAxis.getExtent();
    var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count();
    isNaN(availSize) && (availSize = 0);
    var dataLen = data.count();
    var step = Math.max(1, Math.round(dataLen / 5));

    for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) {
      if (Symbol.getSymbolSize(data, dataIndex)[categoryAxis.isHorizontal() ? 1 : 0] * 1.5 > availSize) {
        return false;
      }
    }

    return true;
  }

  function createLineClipPath(coordSys, hasAnimation, seriesModel) {
    if (coordSys.type === 'cartesian2d') {
      var isHorizontal = coordSys.getBaseAxis().isHorizontal();
      var clipPath = createGridClipPath(coordSys, hasAnimation, seriesModel);

      if (!seriesModel.get('clip', true)) {
        var rectShape = clipPath.shape;
        var expandSize = Math.max(rectShape.width, rectShape.height);

        if (isHorizontal) {
          rectShape.y -= expandSize;
          rectShape.height += expandSize * 2;
        } else {
          rectShape.x -= expandSize;
          rectShape.width += expandSize * 2;
        }
      }

      return clipPath;
    } else {
      return createPolarClipPath(coordSys, hasAnimation, seriesModel);
    }
  }

  var LineView = function (_super) {
    __extends(LineView, _super);

    function LineView() {
      return _super !== null && _super.apply(this, arguments) || this;
    }

    LineView.prototype.init = function () {
      var lineGroup = new Group();
      var symbolDraw = new SymbolDraw();
      this.group.add(symbolDraw.group);
      this._symbolDraw = symbolDraw;
      this._lineGroup = lineGroup;
    };

    LineView.prototype.render = function (seriesModel, ecModel, api) {
      var _this = this;

      var coordSys = seriesModel.coordinateSystem;
      var group = this.group;
      var data = seriesModel.getData();
      var lineStyleModel = seriesModel.getModel('lineStyle');
      var areaStyleModel = seriesModel.getModel('areaStyle');
      var points = data.mapArray(data.getItemLayout);
      var isCoordSysPolar = coordSys.type === 'polar';
      var prevCoordSys = this._coordSys;
      var symbolDraw = this._symbolDraw;
      var polyline = this._polyline;
      var polygon = this._polygon;
      var lineGroup = this._lineGroup;
      var hasAnimation = seriesModel.get('animation');
      var isAreaChart = !areaStyleModel.isEmpty();
      var valueOrigin = areaStyleModel.get('origin');
      var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);
      var stackedOnPoints = getStackedOnPoints(coordSys, data, dataCoordInfo);
      var showSymbol = seriesModel.get('showSymbol');
      var isIgnoreFunc = showSymbol && !isCoordSysPolar && getIsIgnoreFunc(seriesModel, data, coordSys);
      var oldData = this._data;
      oldData && oldData.eachItemGraphicEl(function (el, idx) {
        if (el.__temp) {
          group.remove(el);
          oldData.setItemGraphicEl(idx, null);
        }
      });

      if (!showSymbol) {
        symbolDraw.remove();
      }

      group.add(lineGroup);
      var step = !isCoordSysPolar ? seriesModel.get('step') : false;
      var clipShapeForSymbol;

      if (coordSys && coordSys.getArea && seriesModel.get('clip', true)) {
        clipShapeForSymbol = coordSys.getArea();

        if (clipShapeForSymbol.width != null) {
          clipShapeForSymbol.x -= 0.1;
          clipShapeForSymbol.y -= 0.1;
          clipShapeForSymbol.width += 0.2;
          clipShapeForSymbol.height += 0.2;
        } else if (clipShapeForSymbol.r0) {
          clipShapeForSymbol.r0 -= 0.5;
          clipShapeForSymbol.r += 0.5;
        }
      }

      this._clipShapeForSymbol = clipShapeForSymbol;

      if (!(polyline && prevCoordSys.type === coordSys.type && step === this._step)) {
        showSymbol && symbolDraw.updateData(data, {
          isIgnore: isIgnoreFunc,
          clipShape: clipShapeForSymbol
        });

        if (step) {
          points = turnPointsIntoStep(points, coordSys, step);
          stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);
        }

        polyline = this._newPolyline(points);

        if (isAreaChart) {
          polygon = this._newPolygon(points, stackedOnPoints);
        }

        lineGroup.setClipPath(createLineClipPath(coordSys, true, seriesModel));
      } else {
        if (isAreaChart && !polygon) {
          polygon = this._newPolygon(points, stackedOnPoints);
        } else if (polygon && !isAreaChart) {
          lineGroup.remove(polygon);
          polygon = this._polygon = null;
        }

        lineGroup.setClipPath(createLineClipPath(coordSys, false, seriesModel));
        showSymbol && symbolDraw.updateData(data, {
          isIgnore: isIgnoreFunc,
          clipShape: clipShapeForSymbol
        });
        data.eachItemGraphicEl(function (el) {
          el && el.stopAnimation(null, true);
        });

        if (!isPointsSame(this._stackedOnPoints, stackedOnPoints) || !isPointsSame(this._points, points)) {
          if (hasAnimation) {
            this._updateAnimation(data, stackedOnPoints, coordSys, api, step, valueOrigin);
          } else {
            if (step) {
              points = turnPointsIntoStep(points, coordSys, step);
              stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);
            }

            polyline.setShape({
              points: points
            });
            polygon && polygon.setShape({
              points: points,
              stackedOnPoints: stackedOnPoints
            });
          }
        }
      }

      var visualColor = getVisualGradient(data, coordSys) || data.getVisual('style')[data.getVisual('drawType')];
      var focus = seriesModel.get(['emphasis', 'focus']);
      var blurScope = seriesModel.get(['emphasis', 'blurScope']);
      polyline.useStyle(defaults(lineStyleModel.getLineStyle(), {
        fill: 'none',
        stroke: visualColor,
        lineJoin: 'bevel'
      }));
      setStatesStylesFromModel(polyline, seriesModel, 'lineStyle');
      var shouldBolderOnEmphasis = seriesModel.get(['emphasis', 'lineStyle', 'width']) === 'bolder';

      if (shouldBolderOnEmphasis) {
        var emphasisLineStyle = polyline.getState('emphasis').style;
        emphasisLineStyle.lineWidth = polyline.style.lineWidth + 1;
      }

      getECData(polyline).seriesIndex = seriesModel.seriesIndex;
      enableHoverEmphasis(polyline, focus, blurScope);
      var smooth = getSmooth(seriesModel.get('smooth'));
      polyline.setShape({
        smooth: smooth,
        smoothMonotone: seriesModel.get('smoothMonotone'),
        connectNulls: seriesModel.get('connectNulls')
      });

      if (polygon) {
        var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');
        var stackedOnSmooth = 0;
        polygon.useStyle(defaults(areaStyleModel.getAreaStyle(), {
          fill: visualColor,
          opacity: 0.7,
          lineJoin: 'bevel'
        }));

        if (stackedOnSeries) {
          stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));
        }

        polygon.setShape({
          smooth: smooth,
          stackedOnSmooth: stackedOnSmooth,
          smoothMonotone: seriesModel.get('smoothMonotone'),
          connectNulls: seriesModel.get('connectNulls')
        });
        setStatesStylesFromModel(polygon, seriesModel, 'areaStyle');
        getECData(polygon).seriesIndex = seriesModel.seriesIndex;
        enableHoverEmphasis(polygon, focus, blurScope);
      }

      var changePolyState = function (toState) {
        _this._changePolyState(toState);
      };

      data.eachItemGraphicEl(function (el) {
        el && (el.onHoverStateChange = changePolyState);
      });
      this._data = data;
      this._coordSys = coordSys;
      this._stackedOnPoints = stackedOnPoints;
      this._points = points;
      this._step = step;
      this._valueOrigin = valueOrigin;
    };

    LineView.prototype.dispose = function () {};

    LineView.prototype.highlight = function (seriesModel, ecModel, api, payload) {
      var data = seriesModel.getData();
      var dataIndex = queryDataIndex(data, payload);

      this._changePolyState('emphasis');

      if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {
        var symbol = data.getItemGraphicEl(dataIndex);

        if (!symbol) {
          var pt = data.getItemLayout(dataIndex);

          if (!pt) {
            return;
          }

          if (this._clipShapeForSymbol && !this._clipShapeForSymbol.contain(pt[0], pt[1])) {
            return;
          }

          symbol = new Symbol(data, dataIndex);
          symbol.setPosition(pt);
          symbol.setZ(seriesModel.get('zlevel'), seriesModel.get('z'));
          symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]);
          symbol.__temp = true;
          data.setItemGraphicEl(dataIndex, symbol);
          symbol.stopSymbolAnimation(true);
          this.group.add(symbol);
        }

        symbol.highlight();
      } else {
        ChartView.prototype.highlight.call(this, seriesModel, ecModel, api, payload);
      }
    };

    LineView.prototype.downplay = function (seriesModel, ecModel, api, payload) {
      var data = seriesModel.getData();
      var dataIndex = queryDataIndex(data, payload);

      this._changePolyState('normal');

      if (dataIndex != null && dataIndex >= 0) {
        var symbol = data.getItemGraphicEl(dataIndex);

        if (symbol) {
          if (symbol.__temp) {
            data.setItemGraphicEl(dataIndex, null);
            this.group.remove(symbol);
          } else {
            symbol.downplay();
          }
        }
      } else {
        ChartView.prototype.downplay.call(this, seriesModel, ecModel, api, payload);
      }
    };

    LineView.prototype._changePolyState = function (toState) {
      var polygon = this._polygon;
      setStatesFlag(this._polyline, toState);
      polygon && setStatesFlag(polygon, toState);
    };

    LineView.prototype._newPolyline = function (points) {
      var polyline = this._polyline;

      if (polyline) {
        this._lineGroup.remove(polyline);
      }

      polyline = new ECPolyline({
        shape: {
          points: points
        },
        segmentIgnoreThreshold: 2,
        z2: 10
      });

      this._lineGroup.add(polyline);

      this._polyline = polyline;
      return polyline;
    };

    LineView.prototype._newPolygon = function (points, stackedOnPoints) {
      var polygon = this._polygon;

      if (polygon) {
        this._lineGroup.remove(polygon);
      }

      polygon = new ECPolygon({
        shape: {
          points: points,
          stackedOnPoints: stackedOnPoints
        },
        segmentIgnoreThreshold: 2
      });

      this._lineGroup.add(polygon);

      this._polygon = polygon;
      return polygon;
    };

    LineView.prototype._updateAnimation = function (data, stackedOnPoints, coordSys, api, step, valueOrigin) {
      var polyline = this._polyline;
      var polygon = this._polygon;
      var seriesModel = data.hostModel;
      var diff = lineAnimationDiff(this._data, data, this._stackedOnPoints, stackedOnPoints, this._coordSys, coordSys, this._valueOrigin, valueOrigin);
      var current = diff.current;
      var stackedOnCurrent = diff.stackedOnCurrent;
      var next = diff.next;
      var stackedOnNext = diff.stackedOnNext;

      if (step) {
        current = turnPointsIntoStep(diff.current, coordSys, step);
        stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step);
        next = turnPointsIntoStep(diff.next, coordSys, step);
        stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step);
      }

      if (getBoundingDiff(current, next) > 3000 || polygon && getBoundingDiff(stackedOnCurrent, stackedOnNext) > 3000) {
        polyline.setShape({
          points: next
        });

        if (polygon) {
          polygon.setShape({
            points: next,
            stackedOnPoints: stackedOnNext
          });
        }

        return;
      }

      polyline.shape.__points = diff.current;
      polyline.shape.points = current;
      polyline.stopAnimation();
      updateProps(polyline, {
        shape: {
          points: next
        }
      }, seriesModel);

      if (polygon) {
        polygon.setShape({
          points: current,
          stackedOnPoints: stackedOnCurrent
        });
        polygon.stopAnimation();
        updateProps(polygon, {
          shape: {
            stackedOnPoints: stackedOnNext
          }
        }, seriesModel);

        if (polyline.shape.points !== polygon.shape.points) {
          polygon.shape.points = polyline.shape.points;
        }
      }

      var updatedDataInfo = [];
      var diffStatus = diff.status;

      for (var i = 0; i < diffStatus.length; i++) {
        var cmd = diffStatus[i].cmd;

        if (cmd === '=') {
          var el = data.getItemGraphicEl(diffStatus[i].idx1);

          if (el) {
            updatedDataInfo.push({
              el: el,
              ptIdx: i
            });
          }
        }
      }

      if (polyline.animators && polyline.animators.length) {
        polyline.animators[0].during(function () {
          for (var i = 0; i < updatedDataInfo.length; i++) {
            var el = updatedDataInfo[i].el;
            el.setPosition(polyline.shape.__points[updatedDataInfo[i].ptIdx]);
            el.markRedraw();
          }
        });
      }
    };

    LineView.prototype.remove = function (ecModel) {
      var group = this.group;
      var oldData = this._data;

      this._lineGroup.removeAll();

      this._symbolDraw.remove(true);

      oldData && oldData.eachItemGraphicEl(function (el, idx) {
        if (el.__temp) {
          group.remove(el);
          oldData.setItemGraphicEl(idx, null);
        }
      });
      this._polyline = this._polygon = this._coordSys = this._points = this._stackedOnPoints = this._data = null;
    };

    LineView.type = 'line';
    return LineView;
  }(ChartView);

  ChartView.registerClass(LineView);

  function layoutPoints(seriesType) {
    return {
      seriesType: seriesType,
      plan: createRenderPlanner(),
      reset: function (seriesModel) {
        var data = seriesModel.getData();
        var coordSys = seriesModel.coordinateSystem;
        var pipelineContext = seriesModel.pipelineContext;
        var isLargeRender = pipelineContext.large;

        if (!coordSys) {
          return;
        }

        var dims = map(coordSys.dimensions, function (dim) {
          return data.mapDimension(dim);
        }).slice(0, 2);
        var dimLen = dims.length;
        var stackResultDim = data.getCalculationInfo('stackResultDimension');

        if (isDimensionStacked(data, dims[0])) {
          dims[0] = stackResultDim;
        }

        if (isDimensionStacked(data, dims[1])) {
          dims[1] = stackResultDim;
        }

        return dimLen && {
          progress: function (params, data) {
            var segCount = params.end - params.start;
            var points = isLargeRender && new Float32Array(segCount * dimLen);
            var tmpIn = [];
            var tmpOut = [];

            for (var i = params.start, offset = 0; i < params.end; i++) {
              var point = void 0;

              if (dimLen === 1) {
                var x = data.get(dims[0], i);
                point = !isNaN(x) && coordSys.dataToPoint(x, null, tmpOut);
              } else {
                var x = tmpIn[0] = data.get(dims[0], i);
                var y = tmpIn[1] = data.get(dims[1], i);
                point = !isNaN(x) && !isNaN(y) && coordSys.dataToPoint(tmpIn, null, tmpOut);
              }

              if (isLargeRender) {
                points[offset++] = point ? point[0] : NaN;
                points[offset++] = point ? point[1] : NaN;
              } else {
                data.setItemLayout(i, point && point.slice() || [NaN, NaN]);
              }
            }

            isLargeRender && data.setLayout('symbolPoints', points);
          }
        };
      }
    };
  }

  var samplers = {
    average: function (frame) {
      var sum = 0;
      var count = 0;

      for (var i = 0; i < frame.length; i++) {
        if (!isNaN(frame[i])) {
          sum += frame[i];
          count++;
        }
      }

      return count === 0 ? NaN : sum / count;
    },
    sum: function (frame) {
      var sum = 0;

      for (var i = 0; i < frame.length; i++) {
        sum += frame[i] || 0;
      }

      return sum;
    },
    max: function (frame) {
      var max = -Infinity;

      for (var i = 0; i < frame.length; i++) {
        frame[i] > max && (max = frame[i]);
      }

      return isFinite(max) ? max : NaN;
    },
    min: function (frame) {
      var min = Infinity;

      for (var i = 0; i < frame.length; i++) {
        frame[i] < min && (min = frame[i]);
      }

      return isFinite(min) ? min : NaN;
    },
    nearest: function (frame) {
      return frame[0];
    }
  };

  var indexSampler = function (frame) {
    return Math.round(frame.length / 2);
  };

  function dataSample(seriesType) {
    return {
      seriesType: seriesType,
      reset: function (seriesModel, ecModel, api) {
        var data = seriesModel.getData();
        var sampling = seriesModel.get('sampling');
        var coordSys = seriesModel.coordinateSystem;

        if (coordSys.type === 'cartesian2d' && sampling) {
          var baseAxis = coordSys.getBaseAxis();
          var valueAxis = coordSys.getOtherAxis(baseAxis);
          var extent = baseAxis.getExtent();
          var size = extent[1] - extent[0];
          var rate = Math.round(data.count() / size);

          if (rate > 1) {
            var sampler = void 0;

            if (typeof sampling === 'string') {
              sampler = samplers[sampling];
            } else if (typeof sampling === 'function') {
              sampler = sampling;
            }

            if (sampler) {
              seriesModel.setData(data.downSample(data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler));
            }
          }
        }
      }
    };
  }

  var defaultOption = {
    show: true,
    zlevel: 0,
    z: 0,
    inverse: false,
    name: '',
    nameLocation: 'end',
    nameRotate: null,
    nameTruncate: {
      maxWidth: null,
      ellipsis: '...',
      placeholder: '.'
    },
    nameTextStyle: {},
    nameGap: 15,
    silent: false,
    triggerEvent: false,
    tooltip: {
      show: false
    },
    axisPointer: {},
    axisLine: {
      show: true,
      onZero: true,
      onZeroAxisIndex: null,
      lineStyle: {
        color: '#6E7079',
        width: 1,
        type: 'solid'
      },
      symbol: ['none', 'none'],
      symbolSize: [10, 15]
    },
    axisTick: {
      show: true,
      inside: false,
      length: 5,
      lineStyle: {
        width: 1
      }
    },
    axisLabel: {
      show: true,
      inside: false,
      rotate: 0,
      showMinLabel: null,
      showMaxLabel: null,
      margin: 8,
      fontSize: 12
    },
    splitLine: {
      show: true,
      lineStyle: {
        color: ['#E0E6F1'],
        width: 1,
        type: 'solid'
      }
    },
    splitArea: {
      show: false,
      areaStyle: {
        color: ['rgba(250,250,250,0.2)', 'rgba(210,219,238,0.2)']
      }
    }
  };
  var categoryAxis = merge({
    boundaryGap: true,
    deduplication: null,
    splitLine: {
      show: false
    },
    axisTick: {
      alignWithLabel: false,
      interval: 'auto'
    },
    axisLabel: {
      interval: 'auto'
    }
  }, defaultOption);
  var valueAxis = merge({
    boundaryGap: [0, 0],
    axisLine: {
      show: 'auto'
    },
    axisTick: {
      show: 'auto'
    },
    splitNumber: 5,
    minorTick: {
      show: false,
      splitNumber: 5,
      length: 3,
      lineStyle: {}
    },
    minorSplitLine: {
      show: false,
      lineStyle: {
        color: '#F4F7FD',
        width: 1
      }
    }
  }, defaultOption);
  var timeAxis = merge({
    scale: true,
    splitNumber: 6,
    axisLabel: {
      showMinLabel: false,
      showMaxLabel: false,
      rich: {
        primary: {
          fontWeight: 'bold'
        }
      }
    },
    splitLine: {
      show: false
    }
  }, valueAxis);
  var logAxis = defaults({
    scale: true,
    logBase: 10
  }, valueAxis);
  var axisDefault = {
    category: categoryAxis,
    value: valueAxis,
    time: timeAxis,
    log: logAxis
  };

  var OrdinalMeta = function () {
    function OrdinalMeta(opt) {
      this.categories = opt.categories || [];
      this._needCollect = opt.needCollect;
      this._deduplication = opt.deduplication;
    }

    OrdinalMeta.createByAxisModel = function (axisModel) {
      var option = axisModel.option;
      var data = option.data;
      var categories = data && map(data, getName);
      return new OrdinalMeta({
        categories: categories,
        needCollect: !categories,
        deduplication: option.dedplication !== false
      });
    };

    OrdinalMeta.prototype.getOrdinal = function (category) {
      return this._getOrCreateMap().get(category);
    };

    OrdinalMeta.prototype.parseAndCollect = function (category) {
      var index;
      var needCollect = this._needCollect;

      if (typeof category !== 'string' && !needCollect) {
        return category;
      }

      if (needCollect && !this._deduplication) {
        index = this.categories.length;
        this.categories[index] = category;
        return index;
      }

      var map = this._getOrCreateMap();

      index = map.get(category);

      if (index == null) {
        if (needCollect) {
          index = this.categories.length;
          this.categories[index] = category;
          map.set(category, index);
        } else {
          index = NaN;
        }
      }

      return index;
    };

    OrdinalMeta.prototype._getOrCreateMap = function () {
      return this._map || (this._map = createHashMap(this.categories));
    };

    return OrdinalMeta;
  }();

  function getName(obj) {
    if (isObject(obj) && obj.value != null) {
      return obj.value;
    } else {
      return obj + '';
    }
  }

  var AXIS_TYPES = {
    value: 1,
    category: 1,
    time: 1,
    log: 1
  };

  function axisModelCreator(axisName, BaseAxisModelClass, extraDefaultOption) {
    each(AXIS_TYPES, function (v, axisType) {
      var defaultOption = merge(merge({}, axisDefault[axisType], true), extraDefaultOption, true);

      var AxisModel = function (_super) {
        __extends(AxisModel, _super);

        function AxisModel() {
          var args = [];

          for (var _i = 0; _i < arguments.length; _i++) {
            args[_i] = arguments[_i];
          }

          var _this = _super.apply(this, args) || this;

          _this.type = axisName + 'Axis.' + axisType;
          return _this;
        }

        AxisModel.prototype.mergeDefaultAndTheme = function (option, ecModel) {
          var layoutMode = fetchLayoutMode(this);
          var inputPositionParams = layoutMode ? getLayoutParams(option) : {};
          var themeModel = ecModel.getTheme();
          merge(option, themeModel.get(axisType + 'Axis'));
          merge(option, this.getDefaultOption());
          option.type = getAxisType(option);

          if (layoutMode) {
            mergeLayoutParam(option, inputPositionParams, layoutMode);
          }
        };

        AxisModel.prototype.optionUpdated = function () {
          var thisOption = this.option;

          if (thisOption.type === 'category') {
            this.__ordinalMeta = OrdinalMeta.createByAxisModel(this);
          }
        };

        AxisModel.prototype.getCategories = function (rawData) {
          var option = this.option;

          if (option.type === 'category') {
            if (rawData) {
              return option.data;
            }

            return this.__ordinalMeta.categories;
          }
        };

        AxisModel.prototype.getOrdinalMeta = function () {
          return this.__ordinalMeta;
        };

        AxisModel.type = axisName + 'Axis.' + axisType;
        AxisModel.defaultOption = defaultOption;
        return AxisModel;
      }(BaseAxisModelClass);

      ComponentModel.registerClass(AxisModel);
    });
    ComponentModel.registerSubTypeDefaulter(axisName + 'Axis', getAxisType);
  }

  function getAxisType(option) {
    return option.type || (option.data ? 'category' : 'value');
  }

  var AxisModelCommonMixin = function () {
    function AxisModelCommonMixin() {}

    AxisModelCommonMixin.prototype.getNeedCrossZero = function () {
      var option = this.option;
      return !option.scale;
    };

    AxisModelCommonMixin.prototype.getCoordSysModel = function () {
      return;
    };

    return AxisModelCommonMixin;
  }();

  var CartesianAxisModel = function (_super) {
    __extends(CartesianAxisModel, _super);

    function CartesianAxisModel() {
      return _super !== null && _super.apply(this, arguments) || this;
    }

    CartesianAxisModel.prototype.getCoordSysModel = function () {
      return this.getReferringComponents('grid', SINGLE_REFERRING).models[0];
    };

    CartesianAxisModel.type = 'cartesian2dAxis';
    return CartesianAxisModel;
  }(ComponentModel);

  mixin(CartesianAxisModel, AxisModelCommonMixin);
  var extraOption = {
    offset: 0,
    categorySortInfo: []
  };
  axisModelCreator('x', CartesianAxisModel, extraOption);
  axisModelCreator('y', CartesianAxisModel, extraOption);

  var Scale = function () {
    function Scale(setting) {
      this._setting = setting || {};
      this._extent = [Infinity, -Infinity];
    }

    Scale.prototype.getSetting = function (name) {
      return this._setting[name];
    };

    Scale.prototype.unionExtent = function (other) {
      var extent = this._extent;
      other[0] < extent[0] && (extent[0] = other[0]);
      other[1] > extent[1] && (extent[1] = other[1]);
    };

    Scale.prototype.unionExtentFromData = function (data, dim) {
      this.unionExtent(data.getApproximateExtent(dim));
    };

    Scale.prototype.getExtent = function () {
      return this._extent.slice();
    };

    Scale.prototype.setExtent = function (start, end) {
      var thisExtent = this._extent;

      if (!isNaN(start)) {
        thisExtent[0] = start;
      }

      if (!isNaN(end)) {
        thisExtent[1] = end;
      }
    };

    Scale.prototype.isInExtentRange = function (value) {
      return this._extent[0] <= value && this._extent[1] >= value;
    };

    Scale.prototype.isBlank = function () {
      return this._isBlank;
    };

    Scale.prototype.setBlank = function (isBlank) {
      this._isBlank = isBlank;
    };

    return Scale;
  }();

  enableClassManagement(Scale, {
    registerWhenExtend: true
  });
  var roundNumber = round$1;

  function intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval) {
    var result = {};
    var span = extent[1] - extent[0];
    var interval = result.interval = nice(span / splitNumber, true);

    if (minInterval != null && interval < minInterval) {
      interval = result.interval = minInterval;
    }

    if (maxInterval != null && interval > maxInterval) {
      interval = result.interval = maxInterval;
    }

    var precision = result.intervalPrecision = getIntervalPrecision(interval);
    var niceTickExtent = result.niceTickExtent = [roundNumber(Math.ceil(extent[0] / interval) * interval, precision), roundNumber(Math.floor(extent[1] / interval) * interval, precision)];
    fixExtent(niceTickExtent, extent);
    return result;
  }

  function getIntervalPrecision(interval) {
    return getPrecisionSafe(interval) + 2;
  }

  function clamp(niceTickExtent, idx, extent) {
    niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]);
  }

  function fixExtent(niceTickExtent, extent) {
    !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]);
    !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]);
    clamp(niceTickExtent, 0, extent);
    clamp(niceTickExtent, 1, extent);

    if (niceTickExtent[0] > niceTickExtent[1]) {
      niceTickExtent[0] = niceTickExtent[1];
    }
  }

  function contain$1(val, extent) {
    return val >= extent[0] && val <= extent[1];
  }

  function normalize$1(val, extent) {
    if (extent[1] === extent[0]) {
      return 0.5;
    }

    return (val - extent[0]) / (extent[1] - extent[0]);
  }

  function scale$2(val, extent) {
    return val * (extent[1] - extent[0]) + extent[0];
  }

  var OrdinalScale = function (_super) {
    __extends(OrdinalScale, _super);

    function OrdinalScale(setting) {
      var _this = _super.call(this, setting) || this;

      _this.type = 'ordinal';

      var ordinalMeta = _this.getSetting('ordinalMeta');

      if (!ordinalMeta || isArray(ordinalMeta)) {
        ordinalMeta = new OrdinalMeta({
          categories: ordinalMeta
        });
      }

      _this._ordinalMeta = ordinalMeta;
      _this._categorySortInfo = [];
      _this._extent = _this.getSetting('extent') || [0, ordinalMeta.categories.length - 1];
      return _this;
    }

    OrdinalScale.prototype.parse = function (val) {
      return typeof val === 'string' ? this._ordinalMeta.getOrdinal(val) : Math.round(val);
    };

    OrdinalScale.prototype.contain = function (rank) {
      rank = this.parse(rank);
      return contain$1(rank, this._extent) && this._ordinalMeta.categories[rank] != null;
    };

    OrdinalScale.prototype.normalize = function (val) {
      val = this.getCategoryIndex(this.parse(val));
      return normalize$1(val, this._extent);
    };

    OrdinalScale.prototype.scale = function (val) {
      val = this.getCategoryIndex(val);
      return Math.round(scale$2(val, this._extent));
    };

    OrdinalScale.prototype.getTicks = function () {
      var ticks = [];
      var extent = this._extent;
      var rank = extent[0];

      while (rank <= extent[1]) {
        ticks.push({
          value: this.getCategoryIndex(rank)
        });
        rank++;
      }

      return ticks;
    };

    OrdinalScale.prototype.getMinorTicks = function (splitNumber) {
      return;
    };

    OrdinalScale.prototype.setCategorySortInfo = function (info) {
      this._categorySortInfo = info;
    };

    OrdinalScale.prototype.getCategorySortInfo = function () {
      return this._categorySortInfo;
    };

    OrdinalScale.prototype.getCategoryIndex = function (n) {
      if (this._categorySortInfo.length) {
        return this._categorySortInfo[n].beforeSortIndex;
      } else {
        return n;
      }
    };

    OrdinalScale.prototype.getRawIndex = function (displayIndex) {
      if (this._categorySortInfo.length) {
        return this._categorySortInfo[displayIndex].ordinalNumber;
      } else {
        return displayIndex;
      }
    };

    OrdinalScale.prototype.getLabel = function (tick) {
      if (!this.isBlank()) {
        var rawIndex = this.getRawIndex(tick.value);
        var cateogry = this._ordinalMeta.categories[rawIndex];
        return cateogry == null ? '' : cateogry + '';
      }
    };

    OrdinalScale.prototype.count = function () {
      return this._extent[1] - this._extent[0] + 1;
    };

    OrdinalScale.prototype.unionExtentFromData = function (data, dim) {
      this.unionExtent(data.getApproximateExtent(dim));
    };

    OrdinalScale.prototype.isInExtentRange = function (value) {
      value = this.getCategoryIndex(value);
      return this._extent[0] <= value && this._extent[1] >= value;
    };

    OrdinalScale.prototype.getOrdinalMeta = function () {
      return this._ordinalMeta;
    };

    OrdinalScale.prototype.niceTicks = function () {};

    OrdinalScale.prototype.niceExtent = function () {};

    OrdinalScale.type = 'ordinal';
    return OrdinalScale;
  }(Scale);

  Scale.registerClass(OrdinalScale);
  var roundNumber$1 = round$1;

  var IntervalScale = function (_super) {
    __extends(IntervalScale, _super);

    function IntervalScale() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = 'interval';
      _this._interval = 0;
      _this._intervalPrecision = 2;
      return _this;
    }

    IntervalScale.prototype.parse = function (val) {
      return val;
    };

    IntervalScale.prototype.contain = function (val) {
      return contain$1(val, this._extent);
    };

    IntervalScale.prototype.normalize = function (val) {
      return normalize$1(val, this._extent);
    };

    IntervalScale.prototype.scale = function (val) {
      return scale$2(val, this._extent);
    };

    IntervalScale.prototype.setExtent = function (start, end) {
      var thisExtent = this._extent;

      if (!isNaN(start)) {
        thisExtent[0] = parseFloat(start);
      }

      if (!isNaN(end)) {
        thisExtent[1] = parseFloat(end);
      }
    };

    IntervalScale.prototype.unionExtent = function (other) {
      var extent = this._extent;
      other[0] < extent[0] && (extent[0] = other[0]);
      other[1] > extent[1] && (extent[1] = other[1]);
      this.setExtent(extent[0], extent[1]);
    };

    IntervalScale.prototype.getInterval = function () {
      return this._interval;
    };

    IntervalScale.prototype.setInterval = function (interval) {
      this._interval = interval;
      this._niceExtent = this._extent.slice();
      this._intervalPrecision = getIntervalPrecision(interval);
    };

    IntervalScale.prototype.getTicks = function (expandToNicedExtent) {
      var interval = this._interval;
      var extent = this._extent;
      var niceTickExtent = this._niceExtent;
      var intervalPrecision = this._intervalPrecision;
      var ticks = [];

      if (!interval) {
        return ticks;
      }

      var safeLimit = 10000;

      if (extent[0] < niceTickExtent[0]) {
        if (expandToNicedExtent) {
          ticks.push({
            value: roundNumber$1(niceTickExtent[0] - interval, intervalPrecision)
          });
        } else {
          ticks.push({
            value: extent[0]
          });
        }
      }

      var tick = niceTickExtent[0];

      while (tick <= niceTickExtent[1]) {
        ticks.push({
          value: tick
        });
        tick = roundNumber$1(tick + interval, intervalPrecision);

        if (tick === ticks[ticks.length - 1].value) {
          break;
        }

        if (ticks.length > safeLimit) {
          return [];
        }
      }

      var lastNiceTick = ticks.length ? ticks[ticks.length - 1].value : niceTickExtent[1];

      if (extent[1] > lastNiceTick) {
        if (expandToNicedExtent) {
          ticks.push({
            value: roundNumber$1(lastNiceTick + interval, intervalPrecision)
          });
        } else {
          ticks.push({
            value: extent[1]
          });
        }
      }

      return ticks;
    };

    IntervalScale.prototype.getMinorTicks = function (splitNumber) {
      var ticks = this.getTicks(true);
      var minorTicks = [];
      var extent = this.getExtent();

      for (var i = 1; i < ticks.length; i++) {
        var nextTick = ticks[i];
        var prevTick = ticks[i - 1];
        var count = 0;
        var minorTicksGroup = [];
        var interval = nextTick.value - prevTick.value;
        var minorInterval = interval / splitNumber;

        while (count < splitNumber - 1) {
          var minorTick = roundNumber$1(prevTick.value + (count + 1) * minorInterval);

          if (minorTick > extent[0] && minorTick < extent[1]) {
            minorTicksGroup.push(minorTick);
          }

          count++;
        }

        minorTicks.push(minorTicksGroup);
      }

      return minorTicks;
    };

    IntervalScale.prototype.getLabel = function (data, opt) {
      if (data == null) {
        return '';
      }

      var precision = opt && opt.precision;

      if (precision == null) {
        precision = getPrecisionSafe(data.value) || 0;
      } else if (precision === 'auto') {
        precision = this._intervalPrecision;
      }

      var dataNum = roundNumber$1(data.value, precision, true);
      return addCommas(dataNum);
    };

    IntervalScale.prototype.niceTicks = function (splitNumber, minInterval, maxInterval) {
      splitNumber = splitNumber || 5;
      var extent = this._extent;
      var span = extent[1] - extent[0];

      if (!isFinite(span)) {
        return;
      }

      if (span < 0) {
        span = -span;
        extent.reverse();
      }

      var result = intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval);
      this._intervalPrecision = result.intervalPrecision;
      this._interval = result.interval;
      this._niceExtent = result.niceTickExtent;
    };

    IntervalScale.prototype.niceExtent = function (opt) {
      var extent = this._extent;

      if (extent[0] === extent[1]) {
        if (extent[0] !== 0) {
          var expandSize = extent[0];

          if (!opt.fixMax) {
            extent[1] += expandSize / 2;
            extent[0] -= expandSize / 2;
          } else {
            extent[0] -= expandSize / 2;
          }
        } else {
          extent[1] = 1;
        }
      }

      var span = extent[1] - extent[0];

      if (!isFinite(span)) {
        extent[0] = 0;
        extent[1] = 1;
      }

      this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);
      var interval = this._interval;

      if (!opt.fixMin) {
        extent[0] = roundNumber$1(Math.floor(extent[0] / interval) * interval);
      }

      if (!opt.fixMax) {
        extent[1] = roundNumber$1(Math.ceil(extent[1] / interval) * interval);
      }
    };

    IntervalScale.type = 'interval';
    return IntervalScale;
  }(Scale);

  Scale.registerClass(IntervalScale);
  var STACK_PREFIX = '__ec_stack_';
  var LARGE_BAR_MIN_WIDTH = 0.5;
  var LargeArr = typeof Float32Array !== 'undefined' ? Float32Array : Array;

  function getSeriesStackId(seriesModel) {
    return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex;
  }

  function getAxisKey(axis) {
    return axis.dim + axis.index;
  }

  function prepareLayoutBarSeries(seriesType, ecModel) {
    var seriesModels = [];
    ecModel.eachSeriesByType(seriesType, function (seriesModel) {
      if (isOnCartesian(seriesModel) && !isInLargeMode(seriesModel)) {
        seriesModels.push(seriesModel);
      }
    });
    return seriesModels;
  }

  function getValueAxesMinGaps(barSeries) {
    var axisValues = {};
    each(barSeries, function (seriesModel) {
      var cartesian = seriesModel.coordinateSystem;
      var baseAxis = cartesian.getBaseAxis();

      if (baseAxis.type !== 'time' && baseAxis.type !== 'value') {
        return;
      }

      var data = seriesModel.getData();
      var key = baseAxis.dim + '_' + baseAxis.index;
      var dim = data.mapDimension(baseAxis.dim);

      for (var i = 0, cnt = data.count(); i < cnt; ++i) {
        var value = data.get(dim, i);

        if (!axisValues[key]) {
          axisValues[key] = [value];
        } else {
          axisValues[key].push(value);
        }
      }
    });
    var axisMinGaps = {};

    for (var key in axisValues) {
      if (axisValues.hasOwnProperty(key)) {
        var valuesInAxis = axisValues[key];

        if (valuesInAxis) {
          valuesInAxis.sort(function (a, b) {
            return a - b;
          });
          var min = null;

          for (var j = 1; j < valuesInAxis.length; ++j) {
            var delta = valuesInAxis[j] - valuesInAxis[j - 1];

            if (delta > 0) {
              min = min === null ? delta : Math.min(min, delta);
            }
          }

          axisMinGaps[key] = min;
        }
      }
    }

    return axisMinGaps;
  }

  function makeColumnLayout(barSeries) {
    var axisMinGaps = getValueAxesMinGaps(barSeries);
    var seriesInfoList = [];
    each(barSeries, function (seriesModel) {
      var cartesian = seriesModel.coordinateSystem;
      var baseAxis = cartesian.getBaseAxis();
      var axisExtent = baseAxis.getExtent();
      var bandWidth;

      if (baseAxis.type === 'category') {
        bandWidth = baseAxis.getBandWidth();
      } else if (baseAxis.type === 'value' || baseAxis.type === 'time') {
        var key = baseAxis.dim + '_' + baseAxis.index;
        var minGap = axisMinGaps[key];
        var extentSpan = Math.abs(axisExtent[1] - axisExtent[0]);
        var scale = baseAxis.scale.getExtent();
        var scaleSpan = Math.abs(scale[1] - scale[0]);
        bandWidth = minGap ? extentSpan / scaleSpan * minGap : extentSpan;
      } else {
        var data = seriesModel.getData();
        bandWidth = Math.abs(axisExtent[1] - axisExtent[0]) / data.count();
      }

      var barWidth = parsePercent$2(seriesModel.get('barWidth'), bandWidth);
      var barMaxWidth = parsePercent$2(seriesModel.get('barMaxWidth'), bandWidth);
      var barMinWidth = parsePercent$2(seriesModel.get('barMinWidth') || 1, bandWidth);
      var barGap = seriesModel.get('barGap');
      var barCategoryGap = seriesModel.get('barCategoryGap');
      seriesInfoList.push({
        bandWidth: bandWidth,
        barWidth: barWidth,
        barMaxWidth: barMaxWidth,
        barMinWidth: barMinWidth,
        barGap: barGap,
        barCategoryGap: barCategoryGap,
        axisKey: getAxisKey(baseAxis),
        stackId: getSeriesStackId(seriesModel)
      });
    });
    return doCalBarWidthAndOffset(seriesInfoList);
  }

  function doCalBarWidthAndOffset(seriesInfoList) {
    var columnsMap = {};
    each(seriesInfoList, function (seriesInfo, idx) {
      var axisKey = seriesInfo.axisKey;
      var bandWidth = seriesInfo.bandWidth;
      var columnsOnAxis = columnsMap[axisKey] || {
        bandWidth: bandWidth,
        remainedWidth: bandWidth,
        autoWidthCount: 0,
        categoryGap: null,
        gap: '20%',
        stacks: {}
      };
      var stacks = columnsOnAxis.stacks;
      columnsMap[axisKey] = columnsOnAxis;
      var stackId = seriesInfo.stackId;

      if (!stacks[stackId]) {
        columnsOnAxis.autoWidthCount++;
      }

      stacks[stackId] = stacks[stackId] || {
        width: 0,
        maxWidth: 0
      };
      var barWidth = seriesInfo.barWidth;

      if (barWidth && !stacks[stackId].width) {
        stacks[stackId].width = barWidth;
        barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);
        columnsOnAxis.remainedWidth -= barWidth;
      }

      var barMaxWidth = seriesInfo.barMaxWidth;
      barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);
      var barMinWidth = seriesInfo.barMinWidth;
      barMinWidth && (stacks[stackId].minWidth = barMinWidth);
      var barGap = seriesInfo.barGap;
      barGap != null && (columnsOnAxis.gap = barGap);
      var barCategoryGap = seriesInfo.barCategoryGap;
      barCategoryGap != null && (columnsOnAxis.categoryGap = barCategoryGap);
    });
    var result = {};
    each(columnsMap, function (columnsOnAxis, coordSysName) {
      result[coordSysName] = {};
      var stacks = columnsOnAxis.stacks;
      var bandWidth = columnsOnAxis.bandWidth;
      var categoryGapPercent = columnsOnAxis.categoryGap;

      if (categoryGapPercent == null) {
        var columnCount = keys(stacks).length;
        categoryGapPercent = Math.max(35 - columnCount * 4, 15) + '%';
      }

      var categoryGap = parsePercent$2(categoryGapPercent, bandWidth);
      var barGapPercent = parsePercent$2(columnsOnAxis.gap, 1);
      var remainedWidth = columnsOnAxis.remainedWidth;
      var autoWidthCount = columnsOnAxis.autoWidthCount;
      var autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
      autoWidth = Math.max(autoWidth, 0);
      each(stacks, function (column) {
        var maxWidth = column.maxWidth;
        var minWidth = column.minWidth;

        if (!column.width) {
          var finalWidth = autoWidth;

          if (maxWidth && maxWidth < finalWidth) {
            finalWidth = Math.min(maxWidth, remainedWidth);
          }

          if (minWidth && minWidth > finalWidth) {
            finalWidth = minWidth;
          }

          if (finalWidth !== autoWidth) {
            column.width = finalWidth;
            remainedWidth -= finalWidth + barGapPercent * finalWidth;
            autoWidthCount--;
          }
        } else {
          var finalWidth = column.width;

          if (maxWidth) {
            finalWidth = Math.min(finalWidth, maxWidth);
          }

          if (minWidth) {
            finalWidth = Math.max(finalWidth, minWidth);
          }

          column.width = finalWidth;
          remainedWidth -= finalWidth + barGapPercent * finalWidth;
          autoWidthCount--;
        }
      });
      autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
      autoWidth = Math.max(autoWidth, 0);
      var widthSum = 0;
      var lastColumn;
      each(stacks, function (column, idx) {
        if (!column.width) {
          column.width = autoWidth;
        }

        lastColumn = column;
        widthSum += column.width * (1 + barGapPercent);
      });

      if (lastColumn) {
        widthSum -= lastColumn.width * barGapPercent;
      }

      var offset = -widthSum / 2;
      each(stacks, function (column, stackId) {
        result[coordSysName][stackId] = result[coordSysName][stackId] || {
          bandWidth: bandWidth,
          offset: offset,
          width: column.width
        };
        offset += column.width * (1 + barGapPercent);
      });
    });
    return result;
  }

  function retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) {
    if (barWidthAndOffset && axis) {
      var result = barWidthAndOffset[getAxisKey(axis)];

      if (result != null && seriesModel != null) {
        return result[getSeriesStackId(seriesModel)];
      }

      return result;
    }
  }

  function layout(seriesType, ecModel) {
    var seriesModels = prepareLayoutBarSeries(seriesType, ecModel);
    var barWidthAndOffset = makeColumnLayout(seriesModels);
    var lastStackCoords = {};
    each(seriesModels, function (seriesModel) {
      var data = seriesModel.getData();
      var cartesian = seriesModel.coordinateSystem;
      var baseAxis = cartesian.getBaseAxis();
      var stackId = getSeriesStackId(seriesModel);
      var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId];
      var columnOffset = columnLayoutInfo.offset;
      var columnWidth = columnLayoutInfo.width;
      var valueAxis = cartesian.getOtherAxis(baseAxis);
      var barMinHeight = seriesModel.get('barMinHeight') || 0;
      lastStackCoords[stackId] = lastStackCoords[stackId] || [];
      data.setLayout({
        bandWidth: columnLayoutInfo.bandWidth,
        offset: columnOffset,
        size: columnWidth
      });
      var valueDim = data.mapDimension(valueAxis.dim);
      var baseDim = data.mapDimension(baseAxis.dim);
      var stacked = isDimensionStacked(data, valueDim);
      var isValueAxisH = valueAxis.isHorizontal();
      var valueAxisStart = getValueAxisStart(baseAxis, valueAxis);

      for (var idx = 0, len = data.count(); idx < len; idx++) {
        var value = data.get(valueDim, idx);
        var baseValue = data.get(baseDim, idx);
        var sign = value >= 0 ? 'p' : 'n';
        var baseCoord = valueAxisStart;

        if (stacked) {
          if (!lastStackCoords[stackId][baseValue]) {
            lastStackCoords[stackId][baseValue] = {
              p: valueAxisStart,
              n: valueAxisStart
            };
          }

          baseCoord = lastStackCoords[stackId][baseValue][sign];
        }

        var x = void 0;
        var y = void 0;
        var width = void 0;
        var height = void 0;

        if (isValueAxisH) {
          var coord = cartesian.dataToPoint([value, baseValue]);
          x = baseCoord;
          y = coord[1] + columnOffset;
          width = coord[0] - valueAxisStart;
          height = columnWidth;

          if (Math.abs(width) < barMinHeight) {
            width = (width < 0 ? -1 : 1) * barMinHeight;
          }

          if (!isNaN(width)) {
            stacked && (lastStackCoords[stackId][baseValue][sign] += width);
          }
        } else {
          var coord = cartesian.dataToPoint([baseValue, value]);
          x = coord[0] + columnOffset;
          y = baseCoord;
          width = columnWidth;
          height = coord[1] - valueAxisStart;

          if (Math.abs(height) < barMinHeight) {
            height = (height <= 0 ? -1 : 1) * barMinHeight;
          }

          if (!isNaN(height)) {
            stacked && (lastStackCoords[stackId][baseValue][sign] += height);
          }
        }

        data.setItemLayout(idx, {
          x: x,
          y: y,
          width: width,
          height: height
        });
      }
    });
  }

  var largeLayout = {
    seriesType: 'bar',
    plan: createRenderPlanner(),
    reset: function (seriesModel) {
      if (!isOnCartesian(seriesModel) || !isInLargeMode(seriesModel)) {
        return;
      }

      var data = seriesModel.getData();
      var cartesian = seriesModel.coordinateSystem;
      var coordLayout = cartesian.master.getRect();
      var baseAxis = cartesian.getBaseAxis();
      var valueAxis = cartesian.getOtherAxis(baseAxis);
      var valueDim = data.mapDimension(valueAxis.dim);
      var baseDim = data.mapDimension(baseAxis.dim);
      var valueAxisHorizontal = valueAxis.isHorizontal();
      var valueDimIdx = valueAxisHorizontal ? 0 : 1;
      var barWidth = retrieveColumnLayout(makeColumnLayout([seriesModel]), baseAxis, seriesModel).width;

      if (!(barWidth > LARGE_BAR_MIN_WIDTH)) {
        barWidth = LARGE_BAR_MIN_WIDTH;
      }

      return {
        progress: function (params, data) {
          var count = params.count;
          var largePoints = new LargeArr(count * 2);
          var largeBackgroundPoints = new LargeArr(count * 2);
          var largeDataIndices = new LargeArr(count);
          var dataIndex;
          var coord = [];
          var valuePair = [];
          var pointsOffset = 0;
          var idxOffset = 0;

          while ((dataIndex = params.next()) != null) {
            valuePair[valueDimIdx] = data.get(valueDim, dataIndex);
            valuePair[1 - valueDimIdx] = data.get(baseDim, dataIndex);
            coord = cartesian.dataToPoint(valuePair, null, coord);
            largeBackgroundPoints[pointsOffset] = valueAxisHorizontal ? coordLayout.x + coordLayout.width : coord[0];
            largePoints[pointsOffset++] = coord[0];
            largeBackgroundPoints[pointsOffset] = valueAxisHorizontal ? coord[1] : coordLayout.y + coordLayout.height;
            largePoints[pointsOffset++] = coord[1];
            largeDataIndices[idxOffset++] = dataIndex;
          }

          data.setLayout({
            largePoints: largePoints,
            largeDataIndices: largeDataIndices,
            largeBackgroundPoints: largeBackgroundPoints,
            barWidth: barWidth,
            valueAxisStart: getValueAxisStart(baseAxis, valueAxis),
            backgroundStart: valueAxisHorizontal ? coordLayout.x : coordLayout.y,
            valueAxisHorizontal: valueAxisHorizontal
          });
        }
      };
    }
  };

  function isOnCartesian(seriesModel) {
    return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';
  }

  function isInLargeMode(seriesModel) {
    return seriesModel.pipelineContext && seriesModel.pipelineContext.large;
  }

  function getValueAxisStart(baseAxis, valueAxis, stacked) {
    return valueAxis.toGlobalCoord(valueAxis.dataToCoord(valueAxis.type === 'log' ? 1 : 0));
  }

  var bisect = function (a, x, lo, hi) {
    while (lo < hi) {
      var mid = lo + hi >>> 1;

      if (a[mid][1] < x) {
        lo = mid + 1;
      } else {
        hi = mid;
      }
    }

    return lo;
  };

  var TimeScale = function (_super) {
    __extends(TimeScale, _super);

    function TimeScale() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = 'time';
      return _this;
    }

    TimeScale.prototype.getLabel = function (tick) {
      var useUTC = this.getSetting('useUTC');
      return format(tick.value, fullLeveledFormatter[getDefaultFormatPrecisionOfInterval(getPrimaryTimeUnit(this._minLevelUnit))] || fullLeveledFormatter.second, useUTC);
    };

    TimeScale.prototype.getFormattedLabel = function (tick, idx, labelFormatter) {
      var isUTC = this.getSetting('useUTC');
      var lang = this.getSetting('locale');
      return leveledFormat(tick, idx, labelFormatter, lang, isUTC);
    };

    TimeScale.prototype.getTicks = function (expandToNicedExtent) {
      var interval = this._interval;
      var extent = this._extent;
      var ticks = [];

      if (!interval) {
        return ticks;
      }

      ticks.push({
        value: extent[0],
        level: 0
      });
      var useUTC = this.getSetting('useUTC');
      var innerTicks = getIntervalTicks(this._minLevelUnit, this._approxInterval, useUTC, extent);
      ticks = ticks.concat(innerTicks);
      ticks.push({
        value: extent[1],
        level: 0
      });
      return ticks;
    };

    TimeScale.prototype.niceExtent = function (opt) {
      var extent = this._extent;

      if (extent[0] === extent[1]) {
        extent[0] -= ONE_DAY;
        extent[1] += ONE_DAY;
      }

      if (extent[1] === -Infinity && extent[0] === Infinity) {
        var d = new Date();
        extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());
        extent[0] = extent[1] - ONE_DAY;
      }

      this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);
    };

    TimeScale.prototype.niceTicks = function (approxTickNum, minInterval, maxInterval) {
      approxTickNum = approxTickNum || 10;
      var extent = this._extent;
      var span = extent[1] - extent[0];
      this._approxInterval = span / approxTickNum;

      if (minInterval != null && this._approxInterval < minInterval) {
        this._approxInterval = minInterval;
      }

      if (maxInterval != null && this._approxInterval > maxInterval) {
        this._approxInterval = maxInterval;
      }

      var scaleIntervalsLen = scaleIntervals.length;
      var idx = Math.min(bisect(scaleIntervals, this._approxInterval, 0, scaleIntervalsLen), scaleIntervalsLen - 1);
      this._interval = scaleIntervals[idx][1];
      this._minLevelUnit = scaleIntervals[Math.max(idx - 1, 0)][0];
    };

    TimeScale.prototype.parse = function (val) {
      return +parseDate(val);
    };

    TimeScale.prototype.contain = function (val) {
      return contain$1(this.parse(val), this._extent);
    };

    TimeScale.prototype.normalize = function (val) {
      return normalize$1(this.parse(val), this._extent);
    };

    TimeScale.prototype.scale = function (val) {
      return scale$2(val, this._extent);
    };

    TimeScale.type = 'time';
    return TimeScale;
  }(IntervalScale);

  var scaleIntervals = [['second', ONE_SECOND], ['minute', ONE_MINUTE], ['hour', ONE_HOUR], ['quarter-day', ONE_HOUR * 6], ['half-day', ONE_HOUR * 12], ['day', ONE_DAY * 1.2], ['half-week', ONE_DAY * 3.5], ['week', ONE_DAY * 7], ['month', ONE_DAY * 31], ['quarter', ONE_DAY * 95], ['half-year', ONE_YEAR / 2], ['year', ONE_YEAR]];

  function isUnitValueSame(unit, valueA, valueB, isUTC) {
    var dateA = parseDate(valueA);
    var dateB = parseDate(valueB);

    var isSame = function (unit) {
      return getUnitValue(dateA, unit, isUTC) === getUnitValue(dateB, unit, isUTC);
    };

    var isSameYear = function () {
      return isSame('year');
    };

    var isSameMonth = function () {
      return isSameYear() && isSame('month');
    };

    var isSameDay = function () {
      return isSameMonth() && isSame('day');
    };

    var isSameHour = function () {
      return isSameDay() && isSame('hour');
    };

    var isSameMinute = function () {
      return isSameHour() && isSame('minute');
    };

    var isSameSecond = function () {
      return isSameMinute() && isSame('second');
    };

    var isSameMilliSecond = function () {
      return isSameSecond() && isSame('millisecond');
    };

    switch (unit) {
      case 'year':
        return isSameYear();

      case 'month':
        return isSameMonth();

      case 'day':
        return isSameDay();

      case 'hour':
        return isSameHour();

      case 'minute':
        return isSameMinute();

      case 'second':
        return isSameSecond();

      case 'millisecond':
        return isSameMilliSecond();
    }
  }

  function getDateInterval(approxInterval, daysInMonth) {
    approxInterval /= ONE_DAY;
    return approxInterval > 16 ? 16 : approxInterval > 7.5 ? 7 : approxInterval > 3.5 ? 4 : approxInterval > 1.5 ? 2 : 1;
  }

  function getMonthInterval(approxInterval) {
    var APPROX_ONE_MONTH = 30 * ONE_DAY;
    approxInterval /= APPROX_ONE_MONTH;
    return approxInterval > 6 ? 6 : approxInterval > 3 ? 3 : approxInterval > 2 ? 2 : 1;
  }

  function getHourInterval(approxInterval) {
    approxInterval /= ONE_HOUR;
    return approxInterval > 12 ? 12 : approxInterval > 6 ? 6 : approxInterval > 3.5 ? 4 : approxInterval > 2 ? 2 : 1;
  }

  function getMinutesAndSecondsInterval(approxInterval, isMinutes) {
    approxInterval /= isMinutes ? ONE_MINUTE : ONE_SECOND;
    return approxInterval > 30 ? 30 : approxInterval > 20 ? 20 : approxInterval > 15 ? 15 : approxInterval > 10 ? 10 : approxInterval > 5 ? 5 : approxInterval > 2 ? 2 : 1;
  }

  function getMillisecondsInterval(approxInterval) {
    return nice(approxInterval, true);
  }

  function getFirstTimestampOfUnit(date, unitName, isUTC) {
    var outDate = new Date(date);

    switch (getPrimaryTimeUnit(unitName)) {
      case 'year':
      case 'month':
        outDate[monthSetterName(isUTC)](0);

      case 'day':
        outDate[dateSetterName(isUTC)](1);

      case 'hour':
        outDate[hoursSetterName(isUTC)](0);

      case 'minute':
        outDate[minutesSetterName(isUTC)](0);

      case 'second':
        outDate[secondsSetterName(isUTC)](0);
        outDate[millisecondsSetterName(isUTC)](0);
    }

    return outDate.getTime();
  }

  function getIntervalTicks(bottomUnitName, approxInterval, isUTC, extent) {
    var safeLimit = 10000;
    var unitNames = timeUnits;
    var iter = 0;

    function addTicksInSpan(interval, minTimestamp, maxTimestamp, getMethodName, setMethodName, isDate, out) {
      var date = new Date(minTimestamp);
      var dateTime = minTimestamp;
      var d = date[getMethodName]();

      while (dateTime < maxTimestamp && dateTime <= extent[1]) {
        out.push({
          value: dateTime
        });
        d += interval;
        date[setMethodName](d);
        dateTime = date.getTime();
      }

      out.push({
        value: dateTime,
        notAdd: true
      });
    }

    function addLevelTicks(unitName, lastLevelTicks, levelTicks) {
      var newAddedTicks = [];
      var isFirstLevel = !lastLevelTicks.length;

      if (isUnitValueSame(getPrimaryTimeUnit(unitName), extent[0], extent[1], isUTC)) {
        return;
      }

      if (isFirstLevel) {
        lastLevelTicks = [{
          value: getFirstTimestampOfUnit(new Date(extent[0]), unitName, isUTC)
        }, {
          value: extent[1]
        }];
      }

      for (var i = 0; i < lastLevelTicks.length - 1; i++) {
        var startTick = lastLevelTicks[i].value;
        var endTick = lastLevelTicks[i + 1].value;

        if (startTick === endTick) {
          continue;
        }

        var interval = void 0;
        var getterName = void 0;
        var setterName = void 0;
        var isDate = false;

        switch (unitName) {
          case 'year':
            interval = Math.max(1, Math.round(approxInterval / ONE_DAY / 365));
            getterName = fullYearGetterName(isUTC);
            setterName = fullYearSetterName(isUTC);
            break;

          case 'half-year':
          case 'quarter':
          case 'month':
            interval = getMonthInterval(approxInterval);
            getterName = monthGetterName(isUTC);
            setterName = monthSetterName(isUTC);
            break;

          case 'week':
          case 'half-week':
          case 'day':
            interval = getDateInterval(approxInterval);
            getterName = dateGetterName(isUTC);
            setterName = dateSetterName(isUTC);
            isDate = true;
            break;

          case 'half-day':
          case 'quarter-day':
          case 'hour':
            interval = getHourInterval(approxInterval);
            getterName = hoursGetterName(isUTC);
            setterName = hoursSetterName(isUTC);
            break;

          case 'minute':
            interval = getMinutesAndSecondsInterval(approxInterval, true);
            getterName = minutesGetterName(isUTC);
            setterName = minutesSetterName(isUTC);
            break;

          case 'second':
            interval = getMinutesAndSecondsInterval(approxInterval, false);
            getterName = secondsGetterName(isUTC);
            setterName = secondsSetterName(isUTC);
            break;

          case 'millisecond':
            interval = getMillisecondsInterval(approxInterval);
            getterName = millisecondsGetterName(isUTC);
            setterName = millisecondsSetterName(isUTC);
            break;
        }

        addTicksInSpan(interval, startTick, endTick, getterName, setterName, isDate, newAddedTicks);

        if (unitName === 'year' && levelTicks.length > 1 && i === 0) {
          levelTicks.unshift({
            value: levelTicks[0].value - interval
          });
        }
      }

      for (var i = 0; i < newAddedTicks.length; i++) {
        levelTicks.push(newAddedTicks[i]);
      }

      return newAddedTicks;
    }

    var levelsTicks = [];
    var currentLevelTicks = [];
    var tickCount = 0;
    var lastLevelTickCount = 0;

    for (var i = 0; i < unitNames.length && iter++ < safeLimit; ++i) {
      var primaryTimeUnit = getPrimaryTimeUnit(unitNames[i]);

      if (!isPrimaryTimeUnit(unitNames[i])) {
        continue;
      }

      addLevelTicks(unitNames[i], levelsTicks[levelsTicks.length - 1] || [], currentLevelTicks);
      var nextPrimaryTimeUnit = unitNames[i + 1] ? getPrimaryTimeUnit(unitNames[i + 1]) : null;

      if (primaryTimeUnit !== nextPrimaryTimeUnit) {
        if (currentLevelTicks.length) {
          lastLevelTickCount = tickCount;
          currentLevelTicks.sort(function (a, b) {
            return a.value - b.value;
          });
          var levelTicksRemoveDuplicated = [];

          for (var i_1 = 0; i_1 < currentLevelTicks.length; ++i_1) {
            var tickValue = currentLevelTicks[i_1].value;

            if (i_1 === 0 || currentLevelTicks[i_1 - 1].value !== tickValue) {
              levelTicksRemoveDuplicated.push(currentLevelTicks[i_1]);

              if (tickValue >= extent[0] && tickValue <= extent[1]) {
                tickCount++;
              }
            }
          }

          var targetTickNum = (extent[1] - extent[0]) / approxInterval;

          if (tickCount > targetTickNum * 1.5 && lastLevelTickCount > targetTickNum / 1.5) {
            break;
          }

          levelsTicks.push(levelTicksRemoveDuplicated);

          if (tickCount > targetTickNum || bottomUnitName === unitNames[i]) {
            break;
          }
        }

        currentLevelTicks = [];
      }
    }

    if (true) {
      if (iter >= safeLimit) {
        warn('Exceed safe limit.');
      }
    }

    var levelsTicksInExtent = filter(map(levelsTicks, function (levelTicks) {
      return filter(levelTicks, function (tick) {
        return tick.value >= extent[0] && tick.value <= extent[1] && !tick.notAdd;
      });
    }), function (levelTicks) {
      return levelTicks.length > 0;
    });
    var ticks = [];
    var maxLevel = levelsTicksInExtent.length - 1;

    for (var i = 0; i < levelsTicksInExtent.length; ++i) {
      var levelTicks = levelsTicksInExtent[i];

      for (var k = 0; k < levelTicks.length; ++k) {
        ticks.push({
          value: levelTicks[k].value,
          level: maxLevel - i
        });
      }
    }

    ticks.sort(function (a, b) {
      return a.value - b.value;
    });
    var result = [];

    for (var i = 0; i < ticks.length; ++i) {
      if (i === 0 || ticks[i].value !== ticks[i - 1].value) {
        result.push(ticks[i]);
      }
    }

    return result;
  }

  Scale.registerClass(TimeScale);
  var scaleProto = Scale.prototype;
  var intervalScaleProto = IntervalScale.prototype;
  var getPrecisionSafe$1 = getPrecisionSafe;
  var roundingErrorFix = round$1;
  var mathFloor = Math.floor;
  var mathCeil = Math.ceil;
  var mathPow$1 = Math.pow;
  var mathLog = Math.log;

  var LogScale = function (_super) {
    __extends(LogScale, _super);

    function LogScale() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = 'log';
      _this.base = 10;
      _this._originalScale = new IntervalScale();
      _this._interval = 0;
      return _this;
    }

    LogScale.prototype.getTicks = function (expandToNicedExtent) {
      var originalScale = this._originalScale;
      var extent = this._extent;
      var originalExtent = originalScale.getExtent();
      var ticks = intervalScaleProto.getTicks.call(this, expandToNicedExtent);
      return map(ticks, function (tick) {
        var val = tick.value;
        var powVal = round$1(mathPow$1(this.base, val));
        powVal = val === extent[0] && this._fixMin ? fixRoundingError(powVal, originalExtent[0]) : powVal;
        powVal = val === extent[1] && this._fixMax ? fixRoundingError(powVal, originalExtent[1]) : powVal;
        return {
          value: powVal
        };
      }, this);
    };

    LogScale.prototype.setExtent = function (start, end) {
      var base = this.base;
      start = mathLog(start) / mathLog(base);
      end = mathLog(end) / mathLog(base);
      intervalScaleProto.setExtent.call(this, start, end);
    };

    LogScale.prototype.getExtent = function () {
      var base = this.base;
      var extent = scaleProto.getExtent.call(this);
      extent[0] = mathPow$1(base, extent[0]);
      extent[1] = mathPow$1(base, extent[1]);
      var originalScale = this._originalScale;
      var originalExtent = originalScale.getExtent();
      this._fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));
      this._fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));
      return extent;
    };

    LogScale.prototype.unionExtent = function (extent) {
      this._originalScale.unionExtent(extent);

      var base = this.base;
      extent[0] = mathLog(extent[0]) / mathLog(base);
      extent[1] = mathLog(extent[1]) / mathLog(base);
      scaleProto.unionExtent.call(this, extent);
    };

    LogScale.prototype.unionExtentFromData = function (data, dim) {
      this.unionExtent(data.getApproximateExtent(dim));
    };

    LogScale.prototype.niceTicks = function (approxTickNum) {
      approxTickNum = approxTickNum || 10;
      var extent = this._extent;
      var span = extent[1] - extent[0];

      if (span === Infinity || span <= 0) {
        return;
      }

      var interval = quantity(span);
      var err = approxTickNum / span * interval;

      if (err <= 0.5) {
        interval *= 10;
      }

      while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {
        interval *= 10;
      }

      var niceExtent = [round$1(mathCeil(extent[0] / interval) * interval), round$1(mathFloor(extent[1] / interval) * interval)];
      this._interval = interval;
      this._niceExtent = niceExtent;
    };

    LogScale.prototype.niceExtent = function (opt) {
      intervalScaleProto.niceExtent.call(this, opt);
      this._fixMin = opt.fixMin;
      this._fixMax = opt.fixMax;
    };

    LogScale.prototype.parse = function (val) {
      return val;
    };

    LogScale.prototype.contain = function (val) {
      val = mathLog(val) / mathLog(this.base);
      return contain$1(val, this._extent);
    };

    LogScale.prototype.normalize = function (val) {
      val = mathLog(val) / mathLog(this.base);
      return normalize$1(val, this._extent);
    };

    LogScale.prototype.scale = function (val) {
      val = scale$2(val, this._extent);
      return mathPow$1(this.base, val);
    };

    LogScale.type = 'log';
    return LogScale;
  }(Scale);

  var proto = LogScale.prototype;
  proto.getMinorTicks = intervalScaleProto.getMinorTicks;
  proto.getLabel = intervalScaleProto.getLabel;

  function fixRoundingError(val, originalVal) {
    return roundingErrorFix(val, getPrecisionSafe$1(originalVal));
  }

  Scale.registerClass(LogScale);

  var ScaleRawExtentInfo = function () {
    function ScaleRawExtentInfo(scale, model, originalExtent) {
      this._prepareParams(scale, model, originalExtent);
    }

    ScaleRawExtentInfo.prototype._prepareParams = function (scale, model, dataExtent) {
      if (dataExtent[1] < dataExtent[0]) {
        dataExtent = [NaN, NaN];
      }

      this._dataMin = dataExtent[0];
      this._dataMax = dataExtent[1];
      var isOrdinal = this._isOrdinal = scale.type === 'ordinal';
      this._needCrossZero = model.getNeedCrossZero();
      var modelMinRaw = this._modelMinRaw = model.get('min', true);

      if (isFunction(modelMinRaw)) {
        this._modelMinNum = parseAxisModelMinMax(scale, modelMinRaw({
          min: dataExtent[0],
          max: dataExtent[1]
        }));
      } else if (modelMinRaw !== 'dataMin') {
        this._modelMinNum = parseAxisModelMinMax(scale, modelMinRaw);
      }

      var modelMaxRaw = this._modelMaxRaw = model.get('max', true);

      if (isFunction(modelMaxRaw)) {
        this._modelMaxNum = parseAxisModelMinMax(scale, modelMaxRaw({
          min: dataExtent[0],
          max: dataExtent[1]
        }));
      } else if (modelMaxRaw !== 'dataMax') {
        this._modelMaxNum = parseAxisModelMinMax(scale, modelMaxRaw);
      }

      if (isOrdinal) {
        this._axisDataLen = model.getCategories().length;
      } else {
        var boundaryGap = model.get('boundaryGap');
        var boundaryGapArr = isArray(boundaryGap) ? boundaryGap : [boundaryGap || 0, boundaryGap || 0];

        if (typeof boundaryGapArr[0] === 'boolean' || typeof boundaryGapArr[1] === 'boolean') {
          if (true) {
            console.warn('Boolean type for boundaryGap is only ' + 'allowed for ordinal axis. Please use string in ' + 'percentage instead, e.g., "20%". Currently, ' + 'boundaryGap is set to be 0.');
          }

          this._boundaryGapInner = [0, 0];
        } else {
          this._boundaryGapInner = [parsePercent(boundaryGapArr[0], 1), parsePercent(boundaryGapArr[1], 1)];
        }
      }
    };

    ScaleRawExtentInfo.prototype.calculate = function () {
      var isOrdinal = this._isOrdinal;
      var dataMin = this._dataMin;
      var dataMax = this._dataMax;
      var axisDataLen = this._axisDataLen;
      var boundaryGapInner = this._boundaryGapInner;
      var span = !isOrdinal ? dataMax - dataMin || Math.abs(dataMin) : null;
      var min = this._modelMinRaw === 'dataMin' ? dataMin : this._modelMinNum;
      var max = this._modelMaxRaw === 'dataMax' ? dataMax : this._modelMaxNum;
      var minFixed = min != null;
      var maxFixed = max != null;

      if (min == null) {
        min = isOrdinal ? axisDataLen ? 0 : NaN : dataMin - boundaryGapInner[0] * span;
      }

      if (max == null) {
        max = isOrdinal ? axisDataLen ? axisDataLen - 1 : NaN : dataMax + boundaryGapInner[1] * span;
      }

      (min == null || !isFinite(min)) && (min = NaN);
      (max == null || !isFinite(max)) && (max = NaN);

      if (min > max) {
        min = NaN;
        max = NaN;
      }

      var isBlank = eqNaN(min) || eqNaN(max) || isOrdinal && !axisDataLen;

      if (this._needCrossZero) {
        if (min > 0 && max > 0 && !minFixed) {
          min = 0;
        }

        if (min < 0 && max < 0 && !maxFixed) {
          max = 0;
        }
      }

      var determinedMin = this._determinedMin;
      var determinedMax = this._determinedMax;

      if (determinedMin != null) {
        min = determinedMin;
        minFixed = true;
      }

      if (determinedMax != null) {
        max = determinedMax;
        maxFixed = true;
      }

      return {
        min: min,
        max: max,
        minFixed: minFixed,
        maxFixed: maxFixed,
        isBlank: isBlank
      };
    };

    ScaleRawExtentInfo.prototype.modifyDataMinMax = function (minMaxName, val) {
      if (true) {
        assert(!this.frozen);
      }

      this[DATA_MIN_MAX_ATTR[minMaxName]] = val;
    };

    ScaleRawExtentInfo.prototype.setDeterminedMinMax = function (minMaxName, val) {
      var attr = DETERMINED_MIN_MAX_ATTR[minMaxName];

      if (true) {
        assert(!this.frozen && this[attr] == null);
      }

      this[attr] = val;
    };

    ScaleRawExtentInfo.prototype.freeze = function () {
      this.frozen = true;
    };

    return ScaleRawExtentInfo;
  }();

  var DETERMINED_MIN_MAX_ATTR = {
    min: '_determinedMin',
    max: '_determinedMax'
  };
  var DATA_MIN_MAX_ATTR = {
    min: '_dataMin',
    max: '_dataMax'
  };

  function ensureScaleRawExtentInfo(scale, model, originalExtent) {
    var rawExtentInfo = scale.rawExtentInfo;

    if (rawExtentInfo) {
      return rawExtentInfo;
    }

    rawExtentInfo = new ScaleRawExtentInfo(scale, model, originalExtent);
    scale.rawExtentInfo = rawExtentInfo;
    return rawExtentInfo;
  }

  function parseAxisModelMinMax(scale, minMax) {
    return minMax == null ? null : eqNaN(minMax) ? NaN : scale.parse(minMax);
  }

  function getScaleExtent(scale, model) {
    var scaleType = scale.type;
    var rawExtentResult = ensureScaleRawExtentInfo(scale, model, scale.getExtent()).calculate();
    scale.setBlank(rawExtentResult.isBlank);
    var min = rawExtentResult.min;
    var max = rawExtentResult.max;
    var ecModel = model.ecModel;

    if (ecModel && scaleType === 'time') {
      var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);
      var isBaseAxisAndHasBarSeries_1 = false;
      each(barSeriesModels, function (seriesModel) {
        isBaseAxisAndHasBarSeries_1 = isBaseAxisAndHasBarSeries_1 || seriesModel.getBaseAxis() === model.axis;
      });

      if (isBaseAxisAndHasBarSeries_1) {
        var barWidthAndOffset = makeColumnLayout(barSeriesModels);
        var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);
        min = adjustedScale.min;
        max = adjustedScale.max;
      }
    }

    return {
      extent: [min, max],
      fixMin: rawExtentResult.minFixed,
      fixMax: rawExtentResult.maxFixed
    };
  }

  function adjustScaleForOverflow(min, max, model, barWidthAndOffset) {
    var axisExtent = model.axis.getExtent();
    var axisLength = axisExtent[1] - axisExtent[0];
    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);

    if (barsOnCurrentAxis === undefined) {
      return {
        min: min,
        max: max
      };
    }

    var minOverflow = Infinity;
    each(barsOnCurrentAxis, function (item) {
      minOverflow = Math.min(item.offset, minOverflow);
    });
    var maxOverflow = -Infinity;
    each(barsOnCurrentAxis, function (item) {
      maxOverflow = Math.max(item.offset + item.width, maxOverflow);
    });
    minOverflow = Math.abs(minOverflow);
    maxOverflow = Math.abs(maxOverflow);
    var totalOverFlow = minOverflow + maxOverflow;
    var oldRange = max - min;
    var oldRangePercentOfNew = 1 - (minOverflow + maxOverflow) / axisLength;
    var overflowBuffer = oldRange / oldRangePercentOfNew - oldRange;
    max += overflowBuffer * (maxOverflow / totalOverFlow);
    min -= overflowBuffer * (minOverflow / totalOverFlow);
    return {
      min: min,
      max: max
    };
  }

  function niceScaleExtent(scale, model) {
    var extentInfo = getScaleExtent(scale, model);
    var extent = extentInfo.extent;
    var splitNumber = model.get('splitNumber');

    if (scale instanceof LogScale) {
      scale.base = model.get('logBase');
    }

    var scaleType = scale.type;
    scale.setExtent(extent[0], extent[1]);
    scale.niceExtent({
      splitNumber: splitNumber,
      fixMin: extentInfo.fixMin,
      fixMax: extentInfo.fixMax,
      minInterval: scaleType === 'interval' || scaleType === 'time' ? model.get('minInterval') : null,
      maxInterval: scaleType === 'interval' || scaleType === 'time' ? model.get('maxInterval') : null
    });
    var interval = model.get('interval');

    if (interval != null) {
      scale.setInterval && scale.setInterval(interval);
    }
  }

  function createScaleByModel(model, axisType) {
    axisType = axisType || model.get('type');

    if (axisType) {
      switch (axisType) {
        case 'category':
          return new OrdinalScale({
            ordinalMeta: model.getOrdinalMeta ? model.getOrdinalMeta() : model.getCategories(),
            extent: [Infinity, -Infinity]
          });

        case 'time':
          return new TimeScale({
            locale: model.ecModel.getLocaleModel(),
            useUTC: model.ecModel.get('useUTC')
          });

        default:
          return new (Scale.getClass(axisType) || IntervalScale)();
      }
    }
  }

  function ifAxisCrossZero(axis) {
    var dataExtent = axis.scale.getExtent();
    var min = dataExtent[0];
    var max = dataExtent[1];
    return !(min > 0 && max > 0 || min < 0 && max < 0);
  }

  function makeLabelFormatter(axis) {
    var labelFormatter = axis.getLabelModel().get('formatter');
    var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null;

    if (axis.scale.type === 'time') {
      return function (tpl) {
        return function (tick, idx) {
          return axis.scale.getFormattedLabel(tick, idx, tpl);
        };
      }(labelFormatter);
    } else if (typeof labelFormatter === 'string') {
      return function (tpl) {
        return function (tick) {
          var label = axis.scale.getLabel(tick);
          var text = tpl.replace('{value}', label != null ? label : '');
          return text;
        };
      }(labelFormatter);
    } else if (typeof labelFormatter === 'function') {
      return function (cb) {
        return function (tick, idx) {
          if (categoryTickStart != null) {
            idx = tick.value - categoryTickStart;
          }

          return cb(getAxisRawValue(axis, tick), idx, tick.level != null ? {
            level: tick.level
          } : null);
        };
      }(labelFormatter);
    } else {
      return function (tick) {
        return axis.scale.getLabel(tick);
      };
    }
  }

  function getAxisRawValue(axis, tick) {
    return axis.type === 'category' ? axis.scale.getLabel(tick) : tick.value;
  }

  function estimateLabelUnionRect(axis) {
    var axisModel = axis.model;
    var scale = axis.scale;

    if (!axisModel.get(['axisLabel', 'show']) || scale.isBlank()) {
      return;
    }

    var realNumberScaleTicks;
    var tickCount;
    var categoryScaleExtent = scale.getExtent();

    if (scale instanceof OrdinalScale) {
      tickCount = scale.count();
    } else {
      realNumberScaleTicks = scale.getTicks();
      tickCount = realNumberScaleTicks.length;
    }

    var axisLabelModel = axis.getLabelModel();
    var labelFormatter = makeLabelFormatter(axis);
    var rect;
    var step = 1;

    if (tickCount > 40) {
      step = Math.ceil(tickCount / 40);
    }

    for (var i = 0; i < tickCount; i += step) {
      var tick = realNumberScaleTicks ? realNumberScaleTicks[i] : {
        value: categoryScaleExtent[0] + i
      };
      var label = labelFormatter(tick, i);
      var unrotatedSingleRect = axisLabelModel.getTextRect(label);
      var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);
      rect ? rect.union(singleRect) : rect = singleRect;
    }

    return rect;
  }

  function rotateTextRect(textRect, rotate) {
    var rotateRadians = rotate * Math.PI / 180;
    var beforeWidth = textRect.width;
    var beforeHeight = textRect.height;
    var afterWidth = beforeWidth * Math.cos(rotateRadians) + beforeHeight * Math.sin(rotateRadians);
    var afterHeight = beforeWidth * Math.sin(rotateRadians) + beforeHeight * Math.cos(rotateRadians);
    var rotatedRect = new BoundingRect(textRect.x, textRect.y, afterWidth, afterHeight);
    return rotatedRect;
  }

  function getOptionCategoryInterval(model) {
    var interval = model.get('interval');
    return interval == null ? 'auto' : interval;
  }

  function shouldShowAllLabels(axis) {
    return axis.type === 'category' && getOptionCategoryInterval(axis.getLabelModel()) === 0;
  }

  function getDataDimensionsOnAxis(data, axisDim) {
    var dataDimMap = {};
    each(data.mapDimensionsAll(axisDim), function (dataDim) {
      dataDimMap[getStackedDimension(data, dataDim)] = true;
    });
    return keys(dataDimMap);
  }

  function unionAxisExtentFromData(dataExtent, data, axisDim) {
    if (data) {
      each(getDataDimensionsOnAxis(data, axisDim), function (dim) {
        var seriesExtent = data.getApproximateExtent(dim);
        seriesExtent[0] < dataExtent[0] && (dataExtent[0] = seriesExtent[0]);
        seriesExtent[1] > dataExtent[1] && (dataExtent[1] = seriesExtent[1]);
      });
    }
  }

  var PI$5 = Math.PI;

  var AxisBuilder = function () {
    function AxisBuilder(axisModel, opt) {
      this.group = new Group();
      this.opt = opt;
      this.axisModel = axisModel;
      defaults(opt, {
        labelOffset: 0,
        nameDirection: 1,
        tickDirection: 1,
        labelDirection: 1,
        silent: true,
        handleAutoShown: function () {
          return true;
        }
      });
      var transformGroup = new Group({
        x: opt.position[0],
        y: opt.position[1],
        rotation: opt.rotation
      });
      transformGroup.updateTransform();
      this._transformGroup = transformGroup;
    }

    AxisBuilder.prototype.hasBuilder = function (name) {
      return !!builders[name];
    };

    AxisBuilder.prototype.add = function (name) {
      builders[name](this.opt, this.axisModel, this.group, this._transformGroup);
    };

    AxisBuilder.prototype.getGroup = function () {
      return this.group;
    };

    AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) {
      var rotationDiff = remRadian(textRotation - axisRotation);
      var textAlign;
      var textVerticalAlign;

      if (isRadianAroundZero(rotationDiff)) {
        textVerticalAlign = direction > 0 ? 'top' : 'bottom';
        textAlign = 'center';
      } else if (isRadianAroundZero(rotationDiff - PI$5)) {
        textVerticalAlign = direction > 0 ? 'bottom' : 'top';
        textAlign = 'center';
      } else {
        textVerticalAlign = 'middle';

        if (rotationDiff > 0 && rotationDiff < PI$5) {
          textAlign = direction > 0 ? 'right' : 'left';
        } else {
          textAlign = direction > 0 ? 'left' : 'right';
        }
      }

      return {
        rotation: rotationDiff,
        textAlign: textAlign,
        textVerticalAlign: textVerticalAlign
      };
    };

    AxisBuilder.makeAxisEventDataBase = function (axisModel) {
      var eventData = {
        componentType: axisModel.mainType,
        componentIndex: axisModel.componentIndex
      };
      eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex;
      return eventData;
    };

    AxisBuilder.isLabelSilent = function (axisModel) {
      var tooltipOpt = axisModel.get('tooltip');
      return axisModel.get('silent') || !(axisModel.get('triggerEvent') || tooltipOpt && tooltipOpt.show);
    };

    return AxisBuilder;
  }();

  var builders = {
    axisLine: function (opt, axisModel, group, transformGroup) {
      var shown = axisModel.get(['axisLine', 'show']);

      if (shown === 'auto' && opt.handleAutoShown) {
        shown = opt.handleAutoShown('axisLine');
      }

      if (!shown) {
        return;
      }

      var extent = axisModel.axis.getExtent();
      var matrix = transformGroup.transform;
      var pt1 = [extent[0], 0];
      var pt2 = [extent[1], 0];

      if (matrix) {
        applyTransform(pt1, pt1, matrix);
        applyTransform(pt2, pt2, matrix);
      }

      var lineStyle = extend({
        lineCap: 'round'
      }, axisModel.getModel(['axisLine', 'lineStyle']).getLineStyle());
      var line = new Line({
        subPixelOptimize: true,
        shape: {
          x1: pt1[0],
          y1: pt1[1],
          x2: pt2[0],
          y2: pt2[1]
        },
        style: lineStyle,
        strokeContainThreshold: opt.strokeContainThreshold || 5,
        silent: true,
        z2: 1
      });
      line.anid = 'line';
      group.add(line);
      var arrows = axisModel.get(['axisLine', 'symbol']);
      var arrowSize = axisModel.get(['axisLine', 'symbolSize']);
      var arrowOffset = axisModel.get(['axisLine', 'symbolOffset']) || 0;

      if (typeof arrowOffset === 'number') {
        arrowOffset = [arrowOffset, arrowOffset];
      }

      if (arrows != null) {
        if (typeof arrows === 'string') {
          arrows = [arrows, arrows];
        }

        if (typeof arrowSize === 'string' || typeof arrowSize === 'number') {
          arrowSize = [arrowSize, arrowSize];
        }

        var symbolWidth_1 = arrowSize[0];
        var symbolHeight_1 = arrowSize[1];
        each([{
          rotate: opt.rotation + Math.PI / 2,
          offset: arrowOffset[0],
          r: 0
        }, {
          rotate: opt.rotation - Math.PI / 2,
          offset: arrowOffset[1],
          r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1]))
        }], function (point, index) {
          if (arrows[index] !== 'none' && arrows[index] != null) {
            var symbol = createSymbol(arrows[index], -symbolWidth_1 / 2, -symbolHeight_1 / 2, symbolWidth_1, symbolHeight_1, lineStyle.stroke, true);
            var r = point.r + point.offset;
            symbol.attr({
              rotation: point.rotate,
              x: pt1[0] + r * Math.cos(opt.rotation),
              y: pt1[1] - r * Math.sin(opt.rotation),
              silent: true,
              z2: 11
            });
            group.add(symbol);
          }
        });
      }
    },
    axisTickLabel: function (opt, axisModel, group, transformGroup) {
      var ticksEls = buildAxisMajorTicks(group, transformGroup, axisModel, opt);
      var labelEls = buildAxisLabel(group, transformGroup, axisModel, opt);
      fixMinMaxLabelShow(axisModel, labelEls, ticksEls);
      buildAxisMinorTicks(group, transformGroup, axisModel, opt.tickDirection);
    },
    axisName: function (opt, axisModel, group, transformGroup) {
      var name = retrieve(opt.axisName, axisModel.get('name'));

      if (!name) {
        return;
      }

      var nameLocation = axisModel.get('nameLocation');
      var nameDirection = opt.nameDirection;
      var textStyleModel = axisModel.getModel('nameTextStyle');
      var gap = axisModel.get('nameGap') || 0;
      var extent = axisModel.axis.getExtent();
      var gapSignal = extent[0] > extent[1] ? -1 : 1;
      var pos = [nameLocation === 'start' ? extent[0] - gapSignal * gap : nameLocation === 'end' ? extent[1] + gapSignal * gap : (extent[0] + extent[1]) / 2, isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0];
      var labelLayout;
      var nameRotation = axisModel.get('nameRotate');

      if (nameRotation != null) {
        nameRotation = nameRotation * PI$5 / 180;
      }

      var axisNameAvailableWidth;

      if (isNameLocationCenter(nameLocation)) {
        labelLayout = AxisBuilder.innerTextLayout(opt.rotation, nameRotation != null ? nameRotation : opt.rotation, nameDirection);
      } else {
        labelLayout = endTextLayout(opt.rotation, nameLocation, nameRotation || 0, extent);
        axisNameAvailableWidth = opt.axisNameAvailableWidth;

        if (axisNameAvailableWidth != null) {
          axisNameAvailableWidth = Math.abs(axisNameAvailableWidth / Math.sin(labelLayout.rotation));
          !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null);
        }
      }

      var textFont = textStyleModel.getFont();
      var truncateOpt = axisModel.get('nameTruncate', true) || {};
      var ellipsis = truncateOpt.ellipsis;
      var maxWidth = retrieve(opt.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth);
      var tooltipOpt = axisModel.get('tooltip', true);
      var mainType = axisModel.mainType;
      var formatterParams = {
        componentType: mainType,
        name: name,
        $vars: ['name']
      };
      formatterParams[mainType + 'Index'] = axisModel.componentIndex;
      var textEl = new ZRText({
        x: pos[0],
        y: pos[1],
        rotation: labelLayout.rotation,
        silent: AxisBuilder.isLabelSilent(axisModel),
        style: createTextStyle(textStyleModel, {
          text: name,
          font: textFont,
          overflow: 'truncate',
          width: maxWidth,
          ellipsis: ellipsis,
          fill: textStyleModel.getTextColor() || axisModel.get(['axisLine', 'lineStyle', 'color']),
          align: textStyleModel.get('align') || labelLayout.textAlign,
          verticalAlign: textStyleModel.get('verticalAlign') || labelLayout.textVerticalAlign
        }),
        z2: 1
      });
      textEl.tooltip = tooltipOpt && tooltipOpt.show ? extend({
        content: name,
        formatter: function () {
          return name;
        },
        formatterParams: formatterParams
      }, tooltipOpt) : null;
      textEl.__fullText = name;
      textEl.anid = 'name';

      if (axisModel.get('triggerEvent')) {
        var eventData = AxisBuilder.makeAxisEventDataBase(axisModel);
        eventData.targetType = 'axisName';
        eventData.name = name;
        getECData(textEl).eventData = eventData;
      }

      transformGroup.add(textEl);
      textEl.updateTransform();
      group.add(textEl);
      textEl.decomposeTransform();
    }
  };

  function endTextLayout(rotation, textPosition, textRotate, extent) {
    var rotationDiff = remRadian(textRotate - rotation);
    var textAlign;
    var textVerticalAlign;
    var inverse = extent[0] > extent[1];
    var onLeft = textPosition === 'start' && !inverse || textPosition !== 'start' && inverse;

    if (isRadianAroundZero(rotationDiff - PI$5 / 2)) {
      textVerticalAlign = onLeft ? 'bottom' : 'top';
      textAlign = 'center';
    } else if (isRadianAroundZero(rotationDiff - PI$5 * 1.5)) {
      textVerticalAlign = onLeft ? 'top' : 'bottom';
      textAlign = 'center';
    } else {
      textVerticalAlign = 'middle';

      if (rotationDiff < PI$5 * 1.5 && rotationDiff > PI$5 / 2) {
        textAlign = onLeft ? 'left' : 'right';
      } else {
        textAlign = onLeft ? 'right' : 'left';
      }
    }

    return {
      rotation: rotationDiff,
      textAlign: textAlign,
      textVerticalAlign: textVerticalAlign
    };
  }

  function fixMinMaxLabelShow(axisModel, labelEls, tickEls) {
    if (shouldShowAllLabels(axisModel.axis)) {
      return;
    }

    var showMinLabel = axisModel.get(['axisLabel', 'showMinLabel']);
    var showMaxLabel = axisModel.get(['axisLabel', 'showMaxLabel']);
    labelEls = labelEls || [];
    tickEls = tickEls || [];
    var firstLabel = labelEls[0];
    var nextLabel = labelEls[1];
    var lastLabel = labelEls[labelEls.length - 1];
    var prevLabel = labelEls[labelEls.length - 2];
    var firstTick = tickEls[0];
    var nextTick = tickEls[1];
    var lastTick = tickEls[tickEls.length - 1];
    var prevTick = tickEls[tickEls.length - 2];

    if (showMinLabel === false) {
      ignoreEl(firstLabel);
      ignoreEl(firstTick);
    } else if (isTwoLabelOverlapped(firstLabel, nextLabel)) {
      if (showMinLabel) {
        ignoreEl(nextLabel);
        ignoreEl(nextTick);
      } else {
        ignoreEl(firstLabel);
        ignoreEl(firstTick);
      }
    }

    if (showMaxLabel === false) {
      ignoreEl(lastLabel);
      ignoreEl(lastTick);
    } else if (isTwoLabelOverlapped(prevLabel, lastLabel)) {
      if (showMaxLabel) {
        ignoreEl(prevLabel);
        ignoreEl(prevTick);
      } else {
        ignoreEl(lastLabel);
        ignoreEl(lastTick);
      }
    }
  }

  function ignoreEl(el) {
    el && (el.ignore = true);
  }

  function isTwoLabelOverlapped(current, next) {
    var firstRect = current && current.getBoundingRect().clone();
    var nextRect = next && next.getBoundingRect().clone();

    if (!firstRect || !nextRect) {
      return;
    }

    var mRotationBack = identity([]);
    rotate(mRotationBack, mRotationBack, -current.rotation);
    firstRect.applyTransform(mul([], mRotationBack, current.getLocalTransform()));
    nextRect.applyTransform(mul([], mRotationBack, next.getLocalTransform()));
    return firstRect.intersect(nextRect);
  }

  function isNameLocationCenter(nameLocation) {
    return nameLocation === 'middle' || nameLocation === 'center';
  }

  function createTicks(ticksCoords, tickTransform, tickEndCoord, tickLineStyle, anidPrefix) {
    var tickEls = [];
    var pt1 = [];
    var pt2 = [];

    for (var i = 0; i < ticksCoords.length; i++) {
      var tickCoord = ticksCoords[i].coord;
      pt1[0] = tickCoord;
      pt1[1] = 0;
      pt2[0] = tickCoord;
      pt2[1] = tickEndCoord;

      if (tickTransform) {
        applyTransform(pt1, pt1, tickTransform);
        applyTransform(pt2, pt2, tickTransform);
      }

      var tickEl = new Line({
        subPixelOptimize: true,
        shape: {
          x1: pt1[0],
          y1: pt1[1],
          x2: pt2[0],
          y2: pt2[1]
        },
        style: tickLineStyle,
        z2: 2,
        autoBatch: true,
        silent: true
      });
      tickEl.anid = anidPrefix + '_' + ticksCoords[i].tickValue;
      tickEls.push(tickEl);
    }

    return tickEls;
  }

  function buildAxisMajorTicks(group, transformGroup, axisModel, opt) {
    var axis = axisModel.axis;
    var tickModel = axisModel.getModel('axisTick');
    var shown = tickModel.get('show');

    if (shown === 'auto' && opt.handleAutoShown) {
      shown = opt.handleAutoShown('axisTick');
    }

    if (!shown || axis.scale.isBlank()) {
      return;
    }

    var lineStyleModel = tickModel.getModel('lineStyle');
    var tickEndCoord = opt.tickDirection * tickModel.get('length');
    var ticksCoords = axis.getTicksCoords();
    var ticksEls = createTicks(ticksCoords, transformGroup.transform, tickEndCoord, defaults(lineStyleModel.getLineStyle(), {
      stroke: axisModel.get(['axisLine', 'lineStyle', 'color'])
    }), 'ticks');

    for (var i = 0; i < ticksEls.length; i++) {
      group.add(ticksEls[i]);
    }

    return ticksEls;
  }

  function buildAxisMinorTicks(group, transformGroup, axisModel, tickDirection) {
    var axis = axisModel.axis;
    var minorTickModel = axisModel.getModel('minorTick');

    if (!minorTickModel.get('show') || axis.scale.isBlank()) {
      return;
    }

    var minorTicksCoords = axis.getMinorTicksCoords();

    if (!minorTicksCoords.length) {
      return;
    }

    var lineStyleModel = minorTickModel.getModel('lineStyle');
    var tickEndCoord = tickDirection * minorTickModel.get('length');
    var minorTickLineStyle = defaults(lineStyleModel.getLineStyle(), defaults(axisModel.getModel('axisTick').getLineStyle(), {
      stroke: axisModel.get(['axisLine', 'lineStyle', 'color'])
    }));

    for (var i = 0; i < minorTicksCoords.length; i++) {
      var minorTicksEls = createTicks(minorTicksCoords[i], transformGroup.transform, tickEndCoord, minorTickLineStyle, 'minorticks_' + i);

      for (var k = 0; k < minorTicksEls.length; k++) {
        group.add(minorTicksEls[k]);
      }
    }
  }

  function buildAxisLabel(group, transformGroup, axisModel, opt) {
    var axis = axisModel.axis;
    var show = retrieve(opt.axisLabelShow, axisModel.get(['axisLabel', 'show']));

    if (!show || axis.scale.isBlank()) {
      return;
    }

    var labelModel = axisModel.getModel('axisLabel');
    var labelMargin = labelModel.get('margin');
    var labels = axis.getViewLabels();
    var labelRotation = (retrieve(opt.labelRotate, labelModel.get('rotate')) || 0) * PI$5 / 180;
    var labelLayout = AxisBuilder.innerTextLayout(opt.rotation, labelRotation, opt.labelDirection);
    var rawCategoryData = axisModel.getCategories && axisModel.getCategories(true);
    var labelEls = [];
    var silent = AxisBuilder.isLabelSilent(axisModel);
    var triggerEvent = axisModel.get('triggerEvent');
    each(labels, function (labelItem, index) {
      var tickValue = axis.scale.type === 'ordinal' ? axis.scale.getRawIndex(labelItem.tickValue) : labelItem.tickValue;
      var formattedLabel = labelItem.formattedLabel;
      var rawLabel = labelItem.rawLabel;
      var itemLabelModel = labelModel;

      if (rawCategoryData && rawCategoryData[tickValue]) {
        var rawCategoryItem = rawCategoryData[tickValue];

        if (isObject(rawCategoryItem) && rawCategoryItem.textStyle) {
          itemLabelModel = new Model(rawCategoryItem.textStyle, labelModel, axisModel.ecModel);
        }
      }

      var textColor = itemLabelModel.getTextColor() || axisModel.get(['axisLine', 'lineStyle', 'color']);
      var tickCoord = axis.dataToCoord(tickValue);
      var textEl = new ZRText({
        x: tickCoord,
        y: opt.labelOffset + opt.labelDirection * labelMargin,
        rotation: labelLayout.rotation,
        silent: silent,
        z2: 10,
        style: createTextStyle(itemLabelModel, {
          text: formattedLabel,
          align: itemLabelModel.getShallow('align', true) || labelLayout.textAlign,
          verticalAlign: itemLabelModel.getShallow('verticalAlign', true) || itemLabelModel.getShallow('baseline', true) || labelLayout.textVerticalAlign,
          fill: typeof textColor === 'function' ? textColor(axis.type === 'category' ? rawLabel : axis.type === 'value' ? tickValue + '' : tickValue, index) : textColor
        })
      });
      textEl.anid = 'label_' + tickValue;

      if (triggerEvent) {
        var eventData = AxisBuilder.makeAxisEventDataBase(axisModel);
        eventData.targetType = 'axisLabel';
        eventData.value = rawLabel;
        getECData(textEl).eventData = eventData;
      }

      transformGroup.add(textEl);
      textEl.updateTransform();
      labelEls.push(textEl);
      group.add(textEl);
      textEl.decomposeTransform();
    });
    return labelEls;
  }

  function fixValue(axisModel) {
    var axisInfo = getAxisInfo(axisModel);

    if (!axisInfo) {
      return;
    }

    var axisPointerModel = axisInfo.axisPointerModel;
    var scale = axisInfo.axis.scale;
    var option = axisPointerModel.option;
    var status = axisPointerModel.get('status');
    var value = axisPointerModel.get('value');

    if (value != null) {
      value = scale.parse(value);
    }

    var useHandle = isHandleTrigger(axisPointerModel);

    if (status == null) {
      option.status = useHandle ? 'show' : 'hide';
    }

    var extent = scale.getExtent().slice();
    extent[0] > extent[1] && extent.reverse();

    if (value == null || value > extent[1]) {
      value = extent[1];
    }

    if (value < extent[0]) {
      value = extent[0];
    }

    option.value = value;

    if (useHandle) {
      option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show';
    }
  }

  function getAxisInfo(axisModel) {
    var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo;
    return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];
  }

  function getAxisPointerModel(axisModel) {
    var axisInfo = getAxisInfo(axisModel);
    return axisInfo && axisInfo.axisPointerModel;
  }

  function isHandleTrigger(axisPointerModel) {
    return !!axisPointerModel.get(['handle', 'show']);
  }

  function makeKey(model) {
    return model.type + '||' + model.id;
  }

  var axisPointerClazz = {};

  var AxisView = function (_super) {
    __extends(AxisView, _super);

    function AxisView() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = AxisView.type;
      return _this;
    }

    AxisView.prototype.render = function (axisModel, ecModel, api, payload) {
      this.axisPointerClass && fixValue(axisModel);

      _super.prototype.render.apply(this, arguments);

      this._doUpdateAxisPointerClass(axisModel, api, true);
    };

    AxisView.prototype.updateAxisPointer = function (axisModel, ecModel, api, payload) {
      this._doUpdateAxisPointerClass(axisModel, api, false);
    };

    AxisView.prototype.remove = function (ecModel, api) {
      var axisPointer = this._axisPointer;
      axisPointer && axisPointer.remove(api);
    };

    AxisView.prototype.dispose = function (ecModel, api) {
      this._disposeAxisPointer(api);

      _super.prototype.dispose.apply(this, arguments);
    };

    AxisView.prototype._doUpdateAxisPointerClass = function (axisModel, api, forceRender) {
      var Clazz = AxisView.getAxisPointerClass(this.axisPointerClass);

      if (!Clazz) {
        return;
      }

      var axisPointerModel = getAxisPointerModel(axisModel);
      axisPointerModel ? (this._axisPointer || (this._axisPointer = new Clazz())).render(axisModel, axisPointerModel, api, forceRender) : this._disposeAxisPointer(api);
    };

    AxisView.prototype._disposeAxisPointer = function (api) {
      this._axisPointer && this._axisPointer.dispose(api);
      this._axisPointer = null;
    };

    AxisView.registerAxisPointerClass = function (type, clazz) {
      if (true) {
        if (axisPointerClazz[type]) {
          throw new Error('axisPointer ' + type + ' exists');
        }
      }

      axisPointerClazz[type] = clazz;
    };

    AxisView.getAxisPointerClass = function (type) {
      return type && axisPointerClazz[type];
    };

    AxisView.type = 'axis';
    return AxisView;
  }(ComponentView);

  function layout$1(gridModel, axisModel, opt) {
    opt = opt || {};
    var grid = gridModel.coordinateSystem;
    var axis = axisModel.axis;
    var layout = {};
    var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0];
    var rawAxisPosition = axis.position;
    var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition;
    var axisDim = axis.dim;
    var rect = grid.getRect();
    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];
    var idx = {
      left: 0,
      right: 1,
      top: 0,
      bottom: 1,
      onZero: 2
    };
    var axisOffset = axisModel.get('offset') || 0;
    var posBound = axisDim === 'x' ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset] : [rectBound[0] - axisOffset, rectBound[1] + axisOffset];

    if (otherAxisOnZeroOf) {
      var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0));
      posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]);
    }

    layout.position = [axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0], axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]];
    layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1);
    var dirMap = {
      top: -1,
      bottom: 1,
      left: -1,
      right: 1
    };
    layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];
    layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0;

    if (axisModel.get(['axisTick', 'inside'])) {
      layout.tickDirection = -layout.tickDirection;
    }

    if (retrieve(opt.labelInside, axisModel.get(['axisLabel', 'inside']))) {
      layout.labelDirection = -layout.labelDirection;
    }

    var labelRotate = axisModel.get(['axisLabel', 'rotate']);
    layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate;
    layout.z2 = 1;
    return layout;
  }

  function isCartesian2DSeries(seriesModel) {
    return seriesModel.get('coordinateSystem') === 'cartesian2d';
  }

  function findAxisModels(seriesModel) {
    var axisModelMap = {
      xAxisModel: null,
      yAxisModel: null
    };
    each(axisModelMap, function (v, key) {
      var axisType = key.replace(/Model$/, '');
      var axisModel = seriesModel.getReferringComponents(axisType, SINGLE_REFERRING).models[0];

      if (true) {
        if (!axisModel) {
          throw new Error(axisType + ' "' + retrieve3(seriesModel.get(axisType + 'Index'), seriesModel.get(axisType + 'Id'), 0) + '" not found');
        }
      }

      axisModelMap[key] = axisModel;
    });
    return axisModelMap;
  }

  var inner$5 = makeInner();

  function rectCoordAxisBuildSplitArea(axisView, axisGroup, axisModel, gridModel) {
    var axis = axisModel.axis;

    if (axis.scale.isBlank()) {
      return;
    }

    var splitAreaModel = axisModel.getModel('splitArea');
    var areaStyleModel = splitAreaModel.getModel('areaStyle');
    var areaColors = areaStyleModel.get('color');
    var gridRect = gridModel.coordinateSystem.getRect();
    var ticksCoords = axis.getTicksCoords({
      tickModel: splitAreaModel,
      clamp: true
    });

    if (!ticksCoords.length) {
      return;
    }

    var areaColorsLen = areaColors.length;
    var lastSplitAreaColors = inner$5(axisView).splitAreaColors;
    var newSplitAreaColors = createHashMap();
    var colorIndex = 0;

    if (lastSplitAreaColors) {
      for (var i = 0; i < ticksCoords.length; i++) {
        var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue);

        if (cIndex != null) {
          colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen;
          break;
        }
      }
    }

    var prev = axis.toGlobalCoord(ticksCoords[0].coord);
    var areaStyle = areaStyleModel.getAreaStyle();
    areaColors = isArray(areaColors) ? areaColors : [areaColors];

    for (var i = 1; i < ticksCoords.length; i++) {
      var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);
      var x = void 0;
      var y = void 0;
      var width = void 0;
      var height = void 0;

      if (axis.isHorizontal()) {
        x = prev;
        y = gridRect.y;
        width = tickCoord - x;
        height = gridRect.height;
        prev = x + width;
      } else {
        x = gridRect.x;
        y = prev;
        width = gridRect.width;
        height = tickCoord - y;
        prev = y + height;
      }

      var tickValue = ticksCoords[i - 1].tickValue;
      tickValue != null && newSplitAreaColors.set(tickValue, colorIndex);
      axisGroup.add(new Rect({
        anid: tickValue != null ? 'area_' + tickValue : null,
        shape: {
          x: x,
          y: y,
          width: width,
          height: height
        },
        style: defaults({
          fill: areaColors[colorIndex]
        }, areaStyle),
        autoBatch: true,
        silent: true
      }));
      colorIndex = (colorIndex + 1) % areaColorsLen;
    }

    inner$5(axisView).splitAreaColors = newSplitAreaColors;
  }

  function rectCoordAxisHandleRemove(axisView) {
    inner$5(axisView).splitAreaColors = null;
  }

  var axisBuilderAttrs = ['axisLine', 'axisTickLabel', 'axisName'];
  var selfBuilderAttrs = ['splitArea', 'splitLine', 'minorSplitLine'];

  var CartesianAxisView = function (_super) {
    __extends(CartesianAxisView, _super);

    function CartesianAxisView() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = CartesianAxisView.type;
      _this.axisPointerClass = 'CartesianAxisPointer';
      return _this;
    }

    CartesianAxisView.prototype.render = function (axisModel, ecModel, api, payload) {
      this.group.removeAll();
      var oldAxisGroup = this._axisGroup;
      this._axisGroup = new Group();
      this.group.add(this._axisGroup);

      if (!axisModel.get('show')) {
        return;
      }

      var gridModel = axisModel.getCoordSysModel();
      var layout = layout$1(gridModel, axisModel);
      var axisBuilder = new AxisBuilder(axisModel, extend({
        handleAutoShown: function (elementType) {
          var cartesians = gridModel.coordinateSystem.getCartesians();

          for (var i = 0; i < cartesians.length; i++) {
            var otherAxisType = cartesians[i].getOtherAxis(axisModel.axis).type;

            if (otherAxisType === 'value' || otherAxisType === 'log') {
              return true;
            }
          }

          return false;
        }
      }, layout));
      each(axisBuilderAttrs, axisBuilder.add, axisBuilder);

      this._axisGroup.add(axisBuilder.getGroup());

      each(selfBuilderAttrs, function (name) {
        if (axisModel.get([name, 'show'])) {
          axisElementBuilders[name](this, this._axisGroup, axisModel, gridModel);
        }
      }, this);
      groupTransition(oldAxisGroup, this._axisGroup, axisModel);

      _super.prototype.render.call(this, axisModel, ecModel, api, payload);
    };

    CartesianAxisView.prototype.remove = function () {
      rectCoordAxisHandleRemove(this);
    };

    CartesianAxisView.type = 'cartesianAxis';
    return CartesianAxisView;
  }(AxisView);

  var axisElementBuilders = {
    splitLine: function (axisView, axisGroup, axisModel, gridModel) {
      var axis = axisModel.axis;

      if (axis.scale.isBlank()) {
        return;
      }

      var splitLineModel = axisModel.getModel('splitLine');
      var lineStyleModel = splitLineModel.getModel('lineStyle');
      var lineColors = lineStyleModel.get('color');
      lineColors = isArray(lineColors) ? lineColors : [lineColors];
      var gridRect = gridModel.coordinateSystem.getRect();
      var isHorizontal = axis.isHorizontal();
      var lineCount = 0;
      var ticksCoords = axis.getTicksCoords({
        tickModel: splitLineModel
      });
      var p1 = [];
      var p2 = [];
      var lineStyle = lineStyleModel.getLineStyle();

      for (var i = 0; i < ticksCoords.length; i++) {
        var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);

        if (isHorizontal) {
          p1[0] = tickCoord;
          p1[1] = gridRect.y;
          p2[0] = tickCoord;
          p2[1] = gridRect.y + gridRect.height;
        } else {
          p1[0] = gridRect.x;
          p1[1] = tickCoord;
          p2[0] = gridRect.x + gridRect.width;
          p2[1] = tickCoord;
        }

        var colorIndex = lineCount++ % lineColors.length;
        var tickValue = ticksCoords[i].tickValue;
        axisGroup.add(new Line({
          anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null,
          subPixelOptimize: true,
          autoBatch: true,
          shape: {
            x1: p1[0],
            y1: p1[1],
            x2: p2[0],
            y2: p2[1]
          },
          style: defaults({
            stroke: lineColors[colorIndex]
          }, lineStyle),
          silent: true
        }));
      }
    },
    minorSplitLine: function (axisView, axisGroup, axisModel, gridModel) {
      var axis = axisModel.axis;
      var minorSplitLineModel = axisModel.getModel('minorSplitLine');
      var lineStyleModel = minorSplitLineModel.getModel('lineStyle');
      var gridRect = gridModel.coordinateSystem.getRect();
      var isHorizontal = axis.isHorizontal();
      var minorTicksCoords = axis.getMinorTicksCoords();

      if (!minorTicksCoords.length) {
        return;
      }

      var p1 = [];
      var p2 = [];
      var lineStyle = lineStyleModel.getLineStyle();

      for (var i = 0; i < minorTicksCoords.length; i++) {
        for (var k = 0; k < minorTicksCoords[i].length; k++) {
          var tickCoord = axis.toGlobalCoord(minorTicksCoords[i][k].coord);

          if (isHorizontal) {
            p1[0] = tickCoord;
            p1[1] = gridRect.y;
            p2[0] = tickCoord;
            p2[1] = gridRect.y + gridRect.height;
          } else {
            p1[0] = gridRect.x;
            p1[1] = tickCoord;
            p2[0] = gridRect.x + gridRect.width;
            p2[1] = tickCoord;
          }

          axisGroup.add(new Line({
            anid: 'minor_line_' + minorTicksCoords[i][k].tickValue,
            subPixelOptimize: true,
            autoBatch: true,
            shape: {
              x1: p1[0],
              y1: p1[1],
              x2: p2[0],
              y2: p2[1]
            },
            style: lineStyle,
            silent: true
          }));
        }
      }
    },
    splitArea: function (axisView, axisGroup, axisModel, gridModel) {
      rectCoordAxisBuildSplitArea(axisView, axisGroup, axisModel, gridModel);
    }
  };

  var CartesianXAxisView = function (_super) {
    __extends(CartesianXAxisView, _super);

    function CartesianXAxisView() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = CartesianXAxisView.type;
      return _this;
    }

    CartesianXAxisView.type = 'xAxis';
    return CartesianXAxisView;
  }(CartesianAxisView);

  var CartesianYAxisView = function (_super) {
    __extends(CartesianYAxisView, _super);

    function CartesianYAxisView() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = CartesianXAxisView.type;
      return _this;
    }

    CartesianYAxisView.type = 'yAxis';
    return CartesianYAxisView;
  }(CartesianAxisView);

  ComponentView.registerClass(CartesianXAxisView);
  ComponentView.registerClass(CartesianYAxisView);
  registerProcessor(PRIORITY.PROCESSOR.FILTER + 10, {
    getTargetSeries: function (ecModel) {
      var seriesModelMap = createHashMap();
      ecModel.eachSeries(function (seriesModel) {
        isCartesian2DSeries(seriesModel) && seriesModelMap.set(seriesModel.uid, seriesModel);
      });
      return seriesModelMap;
    },
    overallReset: function (ecModel, api) {
      var seriesRecords = [];
      var axisRecordMap = createHashMap();
      prepareDataExtentOnAxis(ecModel, axisRecordMap, seriesRecords);
      calculateFilteredExtent(axisRecordMap, seriesRecords);
      shrinkAxisExtent(axisRecordMap);
    }
  });

  function prepareDataExtentOnAxis(ecModel, axisRecordMap, seriesRecords) {
    ecModel.eachSeries(function (seriesModel) {
      if (!isCartesian2DSeries(seriesModel)) {
        return;
      }

      var axesModelMap = findAxisModels(seriesModel);
      var xAxisModel = axesModelMap.xAxisModel;
      var yAxisModel = axesModelMap.yAxisModel;
      var xAxis = xAxisModel.axis;
      var yAxis = yAxisModel.axis;
      var xRawExtentInfo = xAxis.scale.rawExtentInfo;
      var yRawExtentInfo = yAxis.scale.rawExtentInfo;
      var data = seriesModel.getData();

      if (xRawExtentInfo && xRawExtentInfo.frozen || yRawExtentInfo && yRawExtentInfo.frozen) {
        return;
      }

      seriesRecords.push({
        seriesModel: seriesModel,
        xAxisModel: xAxisModel,
        yAxisModel: yAxisModel
      });
      unionAxisExtentFromData(prepareAxisRecord(axisRecordMap, xAxisModel).condExtent, data, xAxis.dim);
      unionAxisExtentFromData(prepareAxisRecord(axisRecordMap, yAxisModel).condExtent, data, yAxis.dim);
    });
  }

  function calculateFilteredExtent(axisRecordMap, seriesRecords) {
    each(seriesRecords, function (seriesRecord) {
      var xAxisModel = seriesRecord.xAxisModel;
      var yAxisModel = seriesRecord.yAxisModel;
      var xAxis = xAxisModel.axis;
      var yAxis = yAxisModel.axis;
      var xAxisRecord = prepareAxisRecord(axisRecordMap, xAxisModel);
      var yAxisRecord = prepareAxisRecord(axisRecordMap, yAxisModel);
      xAxisRecord.rawExtentInfo = ensureScaleRawExtentInfo(xAxis.scale, xAxisModel, xAxisRecord.condExtent);
      yAxisRecord.rawExtentInfo = ensureScaleRawExtentInfo(yAxis.scale, yAxisModel, yAxisRecord.condExtent);
      xAxisRecord.rawExtentResult = xAxisRecord.rawExtentInfo.calculate();
      yAxisRecord.rawExtentResult = yAxisRecord.rawExtentInfo.calculate();
      var data = seriesRecord.seriesModel.getData();
      var condDimMap = {};
      var tarDimMap = {};
      var condAxis;
      var tarAxisRecord;

      function addCondition(axis, axisRecord) {
        var condExtent = axisRecord.condExtent;
        var rawExtentResult = axisRecord.rawExtentResult;

        if (axis.type === 'category' && (condExtent[0] < rawExtentResult.min || rawExtentResult.max < condExtent[1])) {
          each(getDataDimensionsOnAxis(data, axis.dim), function (dataDim) {
            if (!hasOwn(condDimMap, dataDim)) {
              condDimMap[dataDim] = true;
              condAxis = axis;
            }
          });
        }
      }

      function addTarget(axis, axisRecord) {
        var rawExtentResult = axisRecord.rawExtentResult;

        if (axis.type !== 'category' && (!rawExtentResult.minFixed || !rawExtentResult.maxFixed)) {
          each(getDataDimensionsOnAxis(data, axis.dim), function (dataDim) {
            if (!hasOwn(condDimMap, dataDim) && !hasOwn(tarDimMap, dataDim)) {
              tarDimMap[dataDim] = true;
              tarAxisRecord = axisRecord;
            }
          });
        }
      }

      addCondition(xAxis, xAxisRecord);
      addCondition(yAxis, yAxisRecord);
      addTarget(xAxis, xAxisRecord);
      addTarget(yAxis, yAxisRecord);
      var condDims = keys(condDimMap);
      var tarDims = keys(tarDimMap);
      var tarDimExtents = map(tarDims, function () {
        return initExtent();
      });
      var condDimsLen = condDims.length;
      var tarDimsLen = tarDims.length;

      if (!condDimsLen || !tarDimsLen) {
        return;
      }

      var singleCondDim = condDimsLen === 1 ? condDims[0] : null;
      var singleTarDim = tarDimsLen === 1 ? tarDims[0] : null;
      var dataLen = data.count();

      if (singleCondDim && singleTarDim) {
        for (var dataIdx = 0; dataIdx < dataLen; dataIdx++) {
          var condVal = data.get(singleCondDim, dataIdx);

          if (condAxis.scale.isInExtentRange(condVal)) {
            unionExtent(tarDimExtents[0], data.get(singleTarDim, dataIdx));
          }
        }
      } else {
        for (var dataIdx = 0; dataIdx < dataLen; dataIdx++) {
          for (var j = 0; j < condDimsLen; j++) {
            var condVal = data.get(condDims[j], dataIdx);

            if (condAxis.scale.isInExtentRange(condVal)) {
              for (var k = 0; k < tarDimsLen; k++) {
                unionExtent(tarDimExtents[k], data.get(tarDims[k], dataIdx));
              }

              break;
            }
          }
        }
      }

      each(tarDimExtents, function (tarDimExtent, i) {
        var dim = tarDims[i];
        data.setApproximateExtent(tarDimExtent, dim);
        var tarAxisExtent = tarAxisRecord.tarExtent = tarAxisRecord.tarExtent || initExtent();
        unionExtent(tarAxisExtent, tarDimExtent[0]);
        unionExtent(tarAxisExtent, tarDimExtent[1]);
      });
    });
  }

  function shrinkAxisExtent(axisRecordMap) {
    axisRecordMap.each(function (axisRecord) {
      var tarAxisExtent = axisRecord.tarExtent;

      if (tarAxisExtent) {
        var rawExtentResult = axisRecord.rawExtentResult;
        var rawExtentInfo = axisRecord.rawExtentInfo;

        if (!rawExtentResult.minFixed && tarAxisExtent[0] > rawExtentResult.min) {
          rawExtentInfo.modifyDataMinMax('min', tarAxisExtent[0]);
        }

        if (!rawExtentResult.maxFixed && tarAxisExtent[1] < rawExtentResult.max) {
          rawExtentInfo.modifyDataMinMax('max', tarAxisExtent[1]);
        }
      }
    });
  }

  function prepareAxisRecord(axisRecordMap, axisModel) {
    return axisRecordMap.get(axisModel.uid) || axisRecordMap.set(axisModel.uid, {
      condExtent: initExtent()
    });
  }

  function initExtent() {
    return [Infinity, -Infinity];
  }

  function unionExtent(extent, val) {
    val < extent[0] && (extent[0] = val);
    val > extent[1] && (extent[1] = val);
  }

  var GridModel = function (_super) {
    __extends(GridModel, _super);

    function GridModel() {
      return _super !== null && _super.apply(this, arguments) || this;
    }

    GridModel.type = 'grid';
    GridModel.dependencies = ['xAxis', 'yAxis'];
    GridModel.layoutMode = 'box';
    GridModel.defaultOption = {
      show: false,
      zlevel: 0,
      z: 0,
      left: '10%',
      top: 60,
      right: '10%',
      bottom: 60,
      containLabel: false,
      backgroundColor: 'rgba(0,0,0,0)',
      borderWidth: 1,
      borderColor: '#ccc'
    };
    return GridModel;
  }(ComponentModel);

  var GridView = function (_super) {
    __extends(GridView, _super);

    function GridView() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = 'grid';
      return _this;
    }

    GridView.prototype.render = function (gridModel, ecModel) {
      this.group.removeAll();

      if (gridModel.get('show')) {
        this.group.add(new Rect({
          shape: gridModel.coordinateSystem.getRect(),
          style: defaults({
            fill: gridModel.get('backgroundColor')
          }, gridModel.getItemStyle()),
          silent: true,
          z2: -1
        }));
      }
    };

    GridView.type = 'grid';
    return GridView;
  }(ComponentView);

  ComponentView.registerClass(GridView);
  ComponentModel.registerClass(GridModel);
  registerPreprocessor(function (option) {
    if (option.xAxis && option.yAxis && !option.grid) {
      option.grid = {};
    }
  });
  registerLayout(layoutPoints('line'));
  registerProcessor(PRIORITY.PROCESSOR.STATISTIC, dataSample('line'));

  var Cartesian = function () {
    function Cartesian(name) {
      this.type = 'cartesian';
      this._dimList = [];
      this._axes = {};
      this.name = name || '';
    }

    Cartesian.prototype.getAxis = function (dim) {
      return this._axes[dim];
    };

    Cartesian.prototype.getAxes = function () {
      return map(this._dimList, function (dim) {
        return this._axes[dim];
      }, this);
    };

    Cartesian.prototype.getAxesByScale = function (scaleType) {
      scaleType = scaleType.toLowerCase();
      return filter(this.getAxes(), function (axis) {
        return axis.scale.type === scaleType;
      });
    };

    Cartesian.prototype.addAxis = function (axis) {
      var dim = axis.dim;
      this._axes[dim] = axis;

      this._dimList.push(dim);
    };

    return Cartesian;
  }();

  var cartesian2DDimensions = ['x', 'y'];

  var Cartesian2D = function (_super) {
    __extends(Cartesian2D, _super);

    function Cartesian2D() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = 'cartesian2d';
      _this.dimensions = cartesian2DDimensions;
      return _this;
    }

    Cartesian2D.prototype.getBaseAxis = function () {
      return this.getAxesByScale('ordinal')[0] || this.getAxesByScale('time')[0] || this.getAxis('x');
    };

    Cartesian2D.prototype.containPoint = function (point) {
      var axisX = this.getAxis('x');
      var axisY = this.getAxis('y');
      return axisX.contain(axisX.toLocalCoord(point[0])) && axisY.contain(axisY.toLocalCoord(point[1]));
    };

    Cartesian2D.prototype.containData = function (data) {
      return this.getAxis('x').containData(data[0]) && this.getAxis('y').containData(data[1]);
    };

    Cartesian2D.prototype.dataToPoint = function (data, reserved, out) {
      var xAxis = this.getAxis('x');
      var yAxis = this.getAxis('y');
      out = out || [];
      out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(data[0]));
      out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(data[1]));
      return out;
    };

    Cartesian2D.prototype.clampData = function (data, out) {
      var xScale = this.getAxis('x').scale;
      var yScale = this.getAxis('y').scale;
      var xAxisExtent = xScale.getExtent();
      var yAxisExtent = yScale.getExtent();
      var x = xScale.parse(data[0]);
      var y = yScale.parse(data[1]);
      out = out || [];
      out[0] = Math.min(Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x), Math.max(xAxisExtent[0], xAxisExtent[1]));
      out[1] = Math.min(Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y), Math.max(yAxisExtent[0], yAxisExtent[1]));
      return out;
    };

    Cartesian2D.prototype.pointToData = function (point, out) {
      var xAxis = this.getAxis('x');
      var yAxis = this.getAxis('y');
      out = out || [];
      out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]));
      out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]));
      return out;
    };

    Cartesian2D.prototype.getOtherAxis = function (axis) {
      return this.getAxis(axis.dim === 'x' ? 'y' : 'x');
    };

    Cartesian2D.prototype.getArea = function () {
      var xExtent = this.getAxis('x').getGlobalExtent();
      var yExtent = this.getAxis('y').getGlobalExtent();
      var x = Math.min(xExtent[0], xExtent[1]);
      var y = Math.min(yExtent[0], yExtent[1]);
      var width = Math.max(xExtent[0], xExtent[1]) - x;
      var height = Math.max(yExtent[0], yExtent[1]) - y;
      return new BoundingRect(x, y, width, height);
    };

    return Cartesian2D;
  }(Cartesian);

  var inner$6 = makeInner();

  function createAxisLabels(axis) {
    return axis.type === 'category' ? makeCategoryLabels(axis) : makeRealNumberLabels(axis);
  }

  function createAxisTicks(axis, tickModel) {
    return axis.type === 'category' ? makeCategoryTicks(axis, tickModel) : {
      ticks: map(axis.scale.getTicks(), function (tick) {
        return tick.value;
      })
    };
  }

  function makeCategoryLabels(axis) {
    var labelModel = axis.getLabelModel();
    var result = makeCategoryLabelsActually(axis, labelModel);
    return !labelModel.get('show') || axis.scale.isBlank() ? {
      labels: [],
      labelCategoryInterval: result.labelCategoryInterval
    } : result;
  }

  function makeCategoryLabelsActually(axis, labelModel) {
    var labelsCache = getListCache(axis, 'labels');
    var optionLabelInterval = getOptionCategoryInterval(labelModel);
    var result = listCacheGet(labelsCache, optionLabelInterval);

    if (result) {
      return result;
    }

    var labels;
    var numericLabelInterval;

    if (isFunction(optionLabelInterval)) {
      labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval);
    } else {
      numericLabelInterval = optionLabelInterval === 'auto' ? makeAutoCategoryInterval(axis) : optionLabelInterval;
      labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval);
    }

    return listCacheSet(labelsCache, optionLabelInterval, {
      labels: labels,
      labelCategoryInterval: numericLabelInterval
    });
  }

  function makeCategoryTicks(axis, tickModel) {
    var ticksCache = getListCache(axis, 'ticks');
    var optionTickInterval = getOptionCategoryInterval(tickModel);
    var result = listCacheGet(ticksCache, optionTickInterval);

    if (result) {
      return result;
    }

    var ticks;
    var tickCategoryInterval;

    if (!tickModel.get('show') || axis.scale.isBlank()) {
      ticks = [];
    }

    if (isFunction(optionTickInterval)) {
      ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true);
    } else if (optionTickInterval === 'auto') {
      var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel());
      tickCategoryInterval = labelsResult.labelCategoryInterval;
      ticks = map(labelsResult.labels, function (labelItem) {
        return labelItem.tickValue;
      });
    } else {
      tickCategoryInterval = optionTickInterval;
      ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true);
    }

    return listCacheSet(ticksCache, optionTickInterval, {
      ticks: ticks,
      tickCategoryInterval: tickCategoryInterval
    });
  }

  function makeRealNumberLabels(axis) {
    var ticks = axis.scale.getTicks();
    var labelFormatter = makeLabelFormatter(axis);
    return {
      labels: map(ticks, function (tick, idx) {
        return {
          formattedLabel: labelFormatter(tick, idx),
          rawLabel: axis.scale.getLabel(tick),
          tickValue: tick.value
        };
      })
    };
  }

  function getListCache(axis, prop) {
    return inner$6(axis)[prop] || (inner$6(axis)[prop] = []);
  }

  function listCacheGet(cache, key) {
    for (var i = 0; i < cache.length; i++) {
      if (cache[i].key === key) {
        return cache[i].value;
      }
    }
  }

  function listCacheSet(cache, key, value) {
    cache.push({
      key: key,
      value: value
    });
    return value;
  }

  function makeAutoCategoryInterval(axis) {
    var result = inner$6(axis).autoInterval;
    return result != null ? result : inner$6(axis).autoInterval = axis.calculateCategoryInterval();
  }

  function calculateCategoryInterval(axis) {
    var params = fetchAutoCategoryIntervalCalculationParams(axis);
    var labelFormatter = makeLabelFormatter(axis);
    var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI;
    var ordinalScale = axis.scale;
    var ordinalExtent = ordinalScale.getExtent();
    var tickCount = ordinalScale.count();

    if (ordinalExtent[1] - ordinalExtent[0] < 1) {
      return 0;
    }

    var step = 1;

    if (tickCount > 40) {
      step = Math.max(1, Math.floor(tickCount / 40));
    }

    var tickValue = ordinalExtent[0];
    var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);
    var unitW = Math.abs(unitSpan * Math.cos(rotation));
    var unitH = Math.abs(unitSpan * Math.sin(rotation));
    var maxW = 0;
    var maxH = 0;

    for (; tickValue <= ordinalExtent[1]; tickValue += step) {
      var width = 0;
      var height = 0;
      var rect = getBoundingRect(labelFormatter({
        value: tickValue
      }), params.font, 'center', 'top');
      width = rect.width * 1.3;
      height = rect.height * 1.3;
      maxW = Math.max(maxW, width, 7);
      maxH = Math.max(maxH, height, 7);
    }

    var dw = maxW / unitW;
    var dh = maxH / unitH;
    isNaN(dw) && (dw = Infinity);
    isNaN(dh) && (dh = Infinity);
    var interval = Math.max(0, Math.floor(Math.min(dw, dh)));
    var cache = inner$6(axis.model);
    var axisExtent = axis.getExtent();
    var lastAutoInterval = cache.lastAutoInterval;
    var lastTickCount = cache.lastTickCount;

    if (lastAutoInterval != null && lastTickCount != null && Math.abs(lastAutoInterval - interval) <= 1 && Math.abs(lastTickCount - tickCount) <= 1 && lastAutoInterval > interval && cache.axisExtent0 === axisExtent[0] && cache.axisExtent1 === axisExtent[1]) {
      interval = lastAutoInterval;
    } else {
      cache.lastTickCount = tickCount;
      cache.lastAutoInterval = interval;
      cache.axisExtent0 = axisExtent[0];
      cache.axisExtent1 = axisExtent[1];
    }

    return interval;
  }

  function fetchAutoCategoryIntervalCalculationParams(axis) {
    var labelModel = axis.getLabelModel();
    return {
      axisRotate: axis.getRotate ? axis.getRotate() : axis.isHorizontal && !axis.isHorizontal() ? 90 : 0,
      labelRotate: labelModel.get('rotate') || 0,
      font: labelModel.getFont()
    };
  }

  function makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) {
    var labelFormatter = makeLabelFormatter(axis);
    var ordinalScale = axis.scale;
    var ordinalExtent = ordinalScale.getExtent();
    var labelModel = axis.getLabelModel();
    var result = [];
    var step = Math.max((categoryInterval || 0) + 1, 1);
    var startTick = ordinalExtent[0];
    var tickCount = ordinalScale.count();

    if (startTick !== 0 && step > 1 && tickCount / step > 2) {
      startTick = Math.round(Math.ceil(startTick / step) * step);
    }

    var showAllLabel = shouldShowAllLabels(axis);
    var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel;
    var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel;

    if (includeMinLabel && startTick !== ordinalExtent[0]) {
      addItem(ordinalExtent[0]);
    }

    var tickValue = startTick;

    for (; tickValue <= ordinalExtent[1]; tickValue += step) {
      addItem(tickValue);
    }

    if (includeMaxLabel && tickValue - step !== ordinalExtent[1]) {
      addItem(ordinalExtent[1]);
    }

    function addItem(tickValue) {
      var tickObj = {
        value: tickValue
      };
      result.push(onlyTick ? tickValue : {
        formattedLabel: labelFormatter(tickObj),
        rawLabel: ordinalScale.getLabel(tickObj),
        tickValue: tickValue
      });
    }

    return result;
  }

  function makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) {
    var ordinalScale = axis.scale;
    var labelFormatter = makeLabelFormatter(axis);
    var result = [];
    each(ordinalScale.getTicks(), function (tick) {
      var rawLabel = ordinalScale.getLabel(tick);
      var tickValue = tick.value;

      if (categoryInterval(tick.value, rawLabel)) {
        result.push(onlyTick ? tickValue : {
          formattedLabel: labelFormatter(tick),
          rawLabel: rawLabel,
          tickValue: tickValue
        });
      }
    });
    return result;
  }

  var NORMALIZED_EXTENT = [0, 1];

  var Axis = function () {
    function Axis(dim, scale, extent) {
      this.onBand = false;
      this.inverse = false;
      this.dim = dim;
      this.scale = scale;
      this._extent = extent || [0, 0];
    }

    Axis.prototype.contain = function (coord) {
      var extent = this._extent;
      var min = Math.min(extent[0], extent[1]);
      var max = Math.max(extent[0], extent[1]);
      return coord >= min && coord <= max;
    };

    Axis.prototype.containData = function (data) {
      return this.scale.contain(data);
    };

    Axis.prototype.getExtent = function () {
      return this._extent.slice();
    };

    Axis.prototype.getPixelPrecision = function (dataExtent) {
      return getPixelPrecision(dataExtent || this.scale.getExtent(), this._extent);
    };

    Axis.prototype.setExtent = function (start, end) {
      var extent = this._extent;
      extent[0] = start;
      extent[1] = end;
    };

    Axis.prototype.dataToCoord = function (data, clamp) {
      var extent = this._extent;
      var scale = this.scale;
      data = scale.normalize(data);

      if (this.onBand && scale.type === 'ordinal') {
        extent = extent.slice();
        fixExtentWithBands(extent, scale.count());
      }

      return linearMap(data, NORMALIZED_EXTENT, extent, clamp);
    };

    Axis.prototype.coordToData = function (coord, clamp) {
      var extent = this._extent;
      var scale = this.scale;

      if (this.onBand && scale.type === 'ordinal') {
        extent = extent.slice();
        fixExtentWithBands(extent, scale.count());
      }

      var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp);
      return this.scale.scale(t);
    };

    Axis.prototype.pointToData = function (point, clamp) {
      return;
    };

    Axis.prototype.getTicksCoords = function (opt) {
      opt = opt || {};
      var tickModel = opt.tickModel || this.getTickModel();
      var result = createAxisTicks(this, tickModel);
      var ticks = result.ticks;
      var ticksCoords = map(ticks, function (tickVal) {
        return {
          coord: this.dataToCoord(this.scale.type === 'ordinal' ? this.scale.getRawIndex(tickVal) : tickVal),
          tickValue: tickVal
        };
      }, this);
      var alignWithLabel = tickModel.get('alignWithLabel');
      fixOnBandTicksCoords(this, ticksCoords, alignWithLabel, opt.clamp);
      return ticksCoords;
    };

    Axis.prototype.getMinorTicksCoords = function () {
      if (this.scale.type === 'ordinal') {
        return [];
      }

      var minorTickModel = this.model.getModel('minorTick');
      var splitNumber = minorTickModel.get('splitNumber');

      if (!(splitNumber > 0 && splitNumber < 100)) {
        splitNumber = 5;
      }

      var minorTicks = this.scale.getMinorTicks(splitNumber);
      var minorTicksCoords = map(minorTicks, function (minorTicksGroup) {
        return map(minorTicksGroup, function (minorTick) {
          return {
            coord: this.dataToCoord(minorTick),
            tickValue: minorTick
          };
        }, this);
      }, this);
      return minorTicksCoords;
    };

    Axis.prototype.getViewLabels = function () {
      return createAxisLabels(this).labels;
    };

    Axis.prototype.getLabelModel = function () {
      return this.model.getModel('axisLabel');
    };

    Axis.prototype.getTickModel = function () {
      return this.model.getModel('axisTick');
    };

    Axis.prototype.getBandWidth = function () {
      var axisExtent = this._extent;
      var dataExtent = this.scale.getExtent();
      var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);
      len === 0 && (len = 1);
      var size = Math.abs(axisExtent[1] - axisExtent[0]);
      return Math.abs(size) / len;
    };

    Axis.prototype.calculateCategoryInterval = function () {
      return calculateCategoryInterval(this);
    };

    return Axis;
  }();

  function fixExtentWithBands(extent, nTick) {
    var size = extent[1] - extent[0];
    var len = nTick;
    var margin = size / len / 2;
    extent[0] += margin;
    extent[1] -= margin;
  }

  function fixOnBandTicksCoords(axis, ticksCoords, alignWithLabel, clamp) {
    var ticksLen = ticksCoords.length;

    if (!axis.onBand || alignWithLabel || !ticksLen) {
      return;
    }

    var axisExtent = axis.getExtent();
    var last;
    var diffSize;

    if (ticksLen === 1) {
      ticksCoords[0].coord = axisExtent[0];
      last = ticksCoords[1] = {
        coord: axisExtent[0]
      };
    } else {
      var crossLen = ticksCoords[ticksLen - 1].tickValue - ticksCoords[0].tickValue;
      var shift_1 = (ticksCoords[ticksLen - 1].coord - ticksCoords[0].coord) / crossLen;
      each(ticksCoords, function (ticksItem) {
        ticksItem.coord -= shift_1 / 2;
      });
      var dataExtent = axis.scale.getExtent();
      diffSize = 1 + dataExtent[1] - ticksCoords[ticksLen - 1].tickValue;
      last = {
        coord: ticksCoords[ticksLen - 1].coord + shift_1 * diffSize
      };
      ticksCoords.push(last);
    }

    var inverse = axisExtent[0] > axisExtent[1];

    if (littleThan(ticksCoords[0].coord, axisExtent[0])) {
      clamp ? ticksCoords[0].coord = axisExtent[0] : ticksCoords.shift();
    }

    if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) {
      ticksCoords.unshift({
        coord: axisExtent[0]
      });
    }

    if (littleThan(axisExtent[1], last.coord)) {
      clamp ? last.coord = axisExtent[1] : ticksCoords.pop();
    }

    if (clamp && littleThan(last.coord, axisExtent[1])) {
      ticksCoords.push({
        coord: axisExtent[1]
      });
    }

    function littleThan(a, b) {
      a = round$1(a);
      b = round$1(b);
      return inverse ? a > b : a < b;
    }
  }

  var Axis2D = function (_super) {
    __extends(Axis2D, _super);

    function Axis2D(dim, scale, coordExtent, axisType, position) {
      var _this = _super.call(this, dim, scale, coordExtent) || this;

      _this.index = 0;
      _this.type = axisType || 'value';
      _this.position = position || 'bottom';
      return _this;
    }

    Axis2D.prototype.isHorizontal = function () {
      var position = this.position;
      return position === 'top' || position === 'bottom';
    };

    Axis2D.prototype.getGlobalExtent = function (asc) {
      var ret = this.getExtent();
      ret[0] = this.toGlobalCoord(ret[0]);
      ret[1] = this.toGlobalCoord(ret[1]);
      asc && ret[0] > ret[1] && ret.reverse();
      return ret;
    };

    Axis2D.prototype.pointToData = function (point, clamp) {
      return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp);
    };

    Axis2D.prototype.setCategorySortInfo = function (info) {
      if (this.type !== 'category') {
        return false;
      }

      this.model.option.categorySortInfo = info;
      this.scale.setCategorySortInfo(info);
    };

    return Axis2D;
  }(Axis);

  var Grid = function () {
    function Grid(gridModel, ecModel, api) {
      this.type = 'grid';
      this._coordsMap = {};
      this._coordsList = [];
      this._axesMap = {};
      this._axesList = [];
      this.axisPointerEnabled = true;
      this.dimensions = cartesian2DDimensions;

      this._initCartesian(gridModel, ecModel, api);

      this.model = gridModel;
    }

    Grid.prototype.getRect = function () {
      return this._rect;
    };

    Grid.prototype.update = function (ecModel, api) {
      var axesMap = this._axesMap;

      this._updateScale(ecModel, this.model);

      each(axesMap.x, function (xAxis) {
        niceScaleExtent(xAxis.scale, xAxis.model);
      });
      each(axesMap.y, function (yAxis) {
        niceScaleExtent(yAxis.scale, yAxis.model);
      });
      var onZeroRecords = {};
      each(axesMap.x, function (xAxis) {
        fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords);
      });
      each(axesMap.y, function (yAxis) {
        fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords);
      });
      this.resize(this.model, api);
    };

    Grid.prototype.resize = function (gridModel, api, ignoreContainLabel) {
      var gridRect = getLayoutRect(gridModel.getBoxLayoutParams(), {
        width: api.getWidth(),
        height: api.getHeight()
      });
      this._rect = gridRect;
      var axesList = this._axesList;
      adjustAxes();

      if (!ignoreContainLabel && gridModel.get('containLabel')) {
        each(axesList, function (axis) {
          if (!axis.model.get(['axisLabel', 'inside'])) {
            var labelUnionRect = estimateLabelUnionRect(axis);

            if (labelUnionRect) {
              var dim = axis.isHorizontal() ? 'height' : 'width';
              var margin = axis.model.get(['axisLabel', 'margin']);
              gridRect[dim] -= labelUnionRect[dim] + margin;

              if (axis.position === 'top') {
                gridRect.y += labelUnionRect.height + margin;
              } else if (axis.position === 'left') {
                gridRect.x += labelUnionRect.width + margin;
              }
            }
          }
        });
        adjustAxes();
      }

      function adjustAxes() {
        each(axesList, function (axis) {
          var isHorizontal = axis.isHorizontal();
          var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];
          var idx = axis.inverse ? 1 : 0;
          axis.setExtent(extent[idx], extent[1 - idx]);
          updateAxisTransform(axis, isHorizontal ? gridRect.x : gridRect.y);
        });
      }
    };

    Grid.prototype.getAxis = function (dim, axisIndex) {
      var axesMapOnDim = this._axesMap[dim];

      if (axesMapOnDim != null) {
        return axesMapOnDim[axisIndex || 0];
      }
    };

    Grid.prototype.getAxes = function () {
      return this._axesList.slice();
    };

    Grid.prototype.getCartesian = function (xAxisIndex, yAxisIndex) {
      if (xAxisIndex != null && yAxisIndex != null) {
        var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
        return this._coordsMap[key];
      }

      if (isObject(xAxisIndex)) {
        yAxisIndex = xAxisIndex.yAxisIndex;
        xAxisIndex = xAxisIndex.xAxisIndex;
      }

      for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {
        if (coordList[i].getAxis('x').index === xAxisIndex || coordList[i].getAxis('y').index === yAxisIndex) {
          return coordList[i];
        }
      }
    };

    Grid.prototype.getCartesians = function () {
      return this._coordsList.slice();
    };

    Grid.prototype.convertToPixel = function (ecModel, finder, value) {
      var target = this._findConvertTarget(finder);

      return target.cartesian ? target.cartesian.dataToPoint(value) : target.axis ? target.axis.toGlobalCoord(target.axis.dataToCoord(value)) : null;
    };

    Grid.prototype.convertFromPixel = function (ecModel, finder, value) {
      var target = this._findConvertTarget(finder);

      return target.cartesian ? target.cartesian.pointToData(value) : target.axis ? target.axis.coordToData(target.axis.toLocalCoord(value)) : null;
    };

    Grid.prototype._findConvertTarget = function (finder) {
      var seriesModel = finder.seriesModel;
      var xAxisModel = finder.xAxisModel || seriesModel && seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0];
      var yAxisModel = finder.yAxisModel || seriesModel && seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0];
      var gridModel = finder.gridModel;
      var coordsList = this._coordsList;
      var cartesian;
      var axis;

      if (seriesModel) {
        cartesian = seriesModel.coordinateSystem;
        indexOf(coordsList, cartesian) < 0 && (cartesian = null);
      } else if (xAxisModel && yAxisModel) {
        cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
      } else if (xAxisModel) {
        axis = this.getAxis('x', xAxisModel.componentIndex);
      } else if (yAxisModel) {
        axis = this.getAxis('y', yAxisModel.componentIndex);
      } else if (gridModel) {
        var grid = gridModel.coordinateSystem;

        if (grid === this) {
          cartesian = this._coordsList[0];
        }
      }

      return {
        cartesian: cartesian,
        axis: axis
      };
    };

    Grid.prototype.containPoint = function (point) {
      var coord = this._coordsList[0];

      if (coord) {
        return coord.containPoint(point);
      }
    };

    Grid.prototype._initCartesian = function (gridModel, ecModel, api) {
      var _this = this;

      var grid = this;
      var axisPositionUsed = {
        left: false,
        right: false,
        top: false,
        bottom: false
      };
      var axesMap = {
        x: {},
        y: {}
      };
      var axesCount = {
        x: 0,
        y: 0
      };
      ecModel.eachComponent('xAxis', createAxisCreator('x'), this);
      ecModel.eachComponent('yAxis', createAxisCreator('y'), this);

      if (!axesCount.x || !axesCount.y) {
        this._axesMap = {};
        this._axesList = [];
        return;
      }

      this._axesMap = axesMap;
      each(axesMap.x, function (xAxis, xAxisIndex) {
        each(axesMap.y, function (yAxis, yAxisIndex) {
          var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
          var cartesian = new Cartesian2D(key);
          cartesian.master = _this;
          cartesian.model = gridModel;
          _this._coordsMap[key] = cartesian;

          _this._coordsList.push(cartesian);

          cartesian.addAxis(xAxis);
          cartesian.addAxis(yAxis);
        });
      });

      function createAxisCreator(dimName) {
        return function (axisModel, idx) {
          if (!isAxisUsedInTheGrid(axisModel, gridModel)) {
            return;
          }

          var axisPosition = axisModel.get('position');

          if (dimName === 'x') {
            if (axisPosition !== 'top' && axisPosition !== 'bottom') {
              axisPosition = axisPositionUsed.bottom ? 'top' : 'bottom';
            }
          } else {
            if (axisPosition !== 'left' && axisPosition !== 'right') {
              axisPosition = axisPositionUsed.left ? 'right' : 'left';
            }
          }

          axisPositionUsed[axisPosition] = true;
          var axis = new Axis2D(dimName, createScaleByModel(axisModel), [0, 0], axisModel.get('type'), axisPosition);
          var isCategory = axis.type === 'category';
          axis.onBand = isCategory && axisModel.get('boundaryGap');
          axis.inverse = axisModel.get('inverse');
          axisModel.axis = axis;
          axis.model = axisModel;
          axis.grid = grid;
          axis.index = idx;

          grid._axesList.push(axis);

          axesMap[dimName][idx] = axis;
          axesCount[dimName]++;
        };
      }
    };

    Grid.prototype._updateScale = function (ecModel, gridModel) {
      each(this._axesList, function (axis) {
        axis.scale.setExtent(Infinity, -Infinity);

        if (axis.type === 'category') {
          var categorySortInfo = axis.model.get('categorySortInfo');
          axis.scale.setCategorySortInfo(categorySortInfo);
        }
      });
      ecModel.eachSeries(function (seriesModel) {
        if (isCartesian2DSeries(seriesModel)) {
          var axesModelMap = findAxisModels(seriesModel);
          var xAxisModel = axesModelMap.xAxisModel;
          var yAxisModel = axesModelMap.yAxisModel;

          if (!isAxisUsedInTheGrid(xAxisModel, gridModel) || !isAxisUsedInTheGrid(yAxisModel, gridModel)) {
            return;
          }

          var cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
          var data = seriesModel.getData();
          var xAxis = cartesian.getAxis('x');
          var yAxis = cartesian.getAxis('y');

          if (data.type === 'list') {
            unionExtent(data, xAxis);
            unionExtent(data, yAxis);
          }
        }
      }, this);

      function unionExtent(data, axis) {
        each(getDataDimensionsOnAxis(data, axis.dim), function (dim) {
          axis.scale.unionExtentFromData(data, dim);
        });
      }
    };

    Grid.prototype.getTooltipAxes = function (dim) {
      var baseAxes = [];
      var otherAxes = [];
      each(this.getCartesians(), function (cartesian) {
        var baseAxis = dim != null && dim !== 'auto' ? cartesian.getAxis(dim) : cartesian.getBaseAxis();
        var otherAxis = cartesian.getOtherAxis(baseAxis);
        indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);
        indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);
      });
      return {
        baseAxes: baseAxes,
        otherAxes: otherAxes
      };
    };

    Grid.create = function (ecModel, api) {
      var grids = [];
      ecModel.eachComponent('grid', function (gridModel, idx) {
        var grid = new Grid(gridModel, ecModel, api);
        grid.name = 'grid_' + idx;
        grid.resize(gridModel, api, true);
        gridModel.coordinateSystem = grid;
        grids.push(grid);
      });
      ecModel.eachSeries(function (seriesModel) {
        if (!isCartesian2DSeries(seriesModel)) {
          return;
        }

        var axesModelMap = findAxisModels(seriesModel);
        var xAxisModel = axesModelMap.xAxisModel;
        var yAxisModel = axesModelMap.yAxisModel;
        var gridModel = xAxisModel.getCoordSysModel();

        if (true) {
          if (!gridModel) {
            throw new Error('Grid "' + retrieve3(xAxisModel.get('gridIndex'), xAxisModel.get('gridId'), 0) + '" not found');
          }

          if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {
            throw new Error('xAxis and yAxis must use the same grid');
          }
        }

        var grid = gridModel.coordinateSystem;
        seriesModel.coordinateSystem = grid.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
      });
      return grids;
    };

    Grid.dimensions = cartesian2DDimensions;
    return Grid;
  }();

  function isAxisUsedInTheGrid(axisModel, gridModel) {
    return axisModel.getCoordSysModel() === gridModel;
  }

  function fixAxisOnZero(axesMap, otherAxisDim, axis, onZeroRecords) {
    axis.getAxesOnZeroOf = function () {
      return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : [];
    };

    var otherAxes = axesMap[otherAxisDim];
    var otherAxisOnZeroOf;
    var axisModel = axis.model;
    var onZero = axisModel.get(['axisLine', 'onZero']);
    var onZeroAxisIndex = axisModel.get(['axisLine', 'onZeroAxisIndex']);

    if (!onZero) {
      return;
    }

    if (onZeroAxisIndex != null) {
      if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) {
        otherAxisOnZeroOf = otherAxes[onZeroAxisIndex];
      }
    } else {
      for (var idx in otherAxes) {
        if (otherAxes.hasOwnProperty(idx) && canOnZeroToAxis(otherAxes[idx]) && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]) {
          otherAxisOnZeroOf = otherAxes[idx];
          break;
        }
      }
    }

    if (otherAxisOnZeroOf) {
      onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true;
    }

    function getOnZeroRecordKey(axis) {
      return axis.dim + '_' + axis.index;
    }
  }

  function canOnZeroToAxis(axis) {
    return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis);
  }

  function updateAxisTransform(axis, coordBase) {
    var axisExtent = axis.getExtent();
    var axisExtentSum = axisExtent[0] + axisExtent[1];
    axis.toGlobalCoord = axis.dim === 'x' ? function (coord) {
      return coord + coordBase;
    } : function (coord) {
      return axisExtentSum - coord + coordBase;
    };
    axis.toLocalCoord = axis.dim === 'x' ? function (coord) {
      return coord - coordBase;
    } : function (coord) {
      return axisExtentSum - coord + coordBase;
    };
  }

  CoordinateSystemManager.register('cartesian2d', Grid);

  var BaseBarSeriesModel = function (_super) {
    __extends(BaseBarSeriesModel, _super);

    function BaseBarSeriesModel() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = BaseBarSeriesModel.type;
      return _this;
    }

    BaseBarSeriesModel.prototype.getInitialData = function (option, ecModel) {
      return createListFromArray(this.getSource(), this, {
        useEncodeDefaulter: true
      });
    };

    BaseBarSeriesModel.prototype.getMarkerPosition = function (value) {
      var coordSys = this.coordinateSystem;

      if (coordSys) {
        var pt = coordSys.dataToPoint(coordSys.clampData(value));
        var data = this.getData();
        var offset = data.getLayout('offset');
        var size = data.getLayout('size');
        var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1;
        pt[offsetIndex] += offset + size / 2;
        return pt;
      }

      return [NaN, NaN];
    };

    BaseBarSeriesModel.type = 'series.__base_bar__';
    BaseBarSeriesModel.defaultOption = {
      zlevel: 0,
      z: 2,
      coordinateSystem: 'cartesian2d',
      legendHoverLink: true,
      barMinHeight: 0,
      barMinAngle: 0,
      large: false,
      largeThreshold: 400,
      progressive: 3e3,
      progressiveChunkMode: 'mod'
    };
    return BaseBarSeriesModel;
  }(SeriesModel);

  SeriesModel.registerClass(BaseBarSeriesModel);

  var BarSeriesModel = function (_super) {
    __extends(BarSeriesModel, _super);

    function BarSeriesModel() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.type = BarSeriesModel.type;
      return _this;
    }

    BarSeriesModel.prototype.getProgressive = function () {
      return this.get('large') ? this.get('progressive') : false;
    };

    BarSeriesModel.prototype.getProgressiveThreshold = function () {
      var progressiveThreshold = this.get('progressiveThreshold');
      var largeThreshold = this.get('largeThreshold');

      if (largeThreshold > progressiveThreshold) {
        progressiveThreshold = largeThreshold;
      }

      return progressiveThreshold;
    };

    BarSeriesModel.prototype.brushSelector = function (dataIndex, data, selectors) {
      return selectors.rect(data.getItemLayout(dataIndex));
    };

    BarSeriesModel.type = 'series.bar';
    BarSeriesModel.dependencies = ['grid', 'polar'];
    BarSeriesModel.defaultOption = inheritDefaultOption(BaseBarSeriesModel.defaultOption, {
      clip: true,
      roundCap: false,
      showBackground: false,
      backgroundStyle: {
        color: 'rgba(180, 180, 180, 0.2)',
        borderColor: null,
        borderWidth: 0,
        borderType: 'solid',
        borderRadius: 0,
        shadowBlur: 0,
        shadowColor: null,
        shadowOffsetX: 0,
        shadowOffsetY: 0,
        opacity: 1
      },
      select: {
        itemStyle: {
          borderColor: '#212121'
        }
      },
      realtimeSort: false
    });
    return BarSeriesModel;
  }(BaseBarSeriesModel);

  SeriesModel.registerClass(BarSeriesModel);

  var SausageShape = function () {
    function SausageShape() {
      this.cx = 0;
      this.cy = 0;
      this.r0 = 0;
      this.r = 0;
      this.startAngle = 0;
      this.endAngle = Math.PI * 2;
      this.clockwise = true;
    }

    return SausageShape;
  }();

  var SausagePath = function (_super) {
    __extends(SausagePath, _super);

    function SausagePath(opts) {
      var _this = _super.call(this, opts) || this;

      _this.type = 'sausage';
      return _this;
    }

    SausagePath.prototype.getDefaultShape = function () {
      return new SausageShape();
    };

    SausagePath.prototype.buildPath = function (ctx, shape) {
      var x = shape.cx;
      var y = shape.cy;
      var r0 = Math.max(shape.r0 || 0, 0);
      var r = Math.max(shape.r, 0);
      var dr = (r - r0) * 0.5;
      var rCenter = r0 + dr;
      var startAngle = shape.startAngle;
      var endAngle = shape.endAngle;
      var clockwise = shape.clockwise;
      var unitStartX = Math.cos(startAngle);
      var unitStartY = Math.sin(startAngle);
      var unitEndX = Math.cos(endAngle);
      var unitEndY = Math.sin(endAngle);
      var lessThanCircle = clockwise ? endAngle - startAngle < Math.PI * 2 : startAngle - endAngle < Math.PI * 2;

      if (lessThanCircle) {
        ctx.moveTo(unitStartX * r0 + x, unitStartY * r0 + y);
        ctx.arc(unitStartX * rCenter + x, unitStartY * rCenter + y, dr, -Math.PI + startAngle, startAngle, !clockwise);
      }

      ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
      ctx.moveTo(unitEndX * r + x, unitEndY * r + y);
      ctx.arc(unitEndX * rCenter + x, unitEndY * rCenter + y, dr, endAngle - Math.PI * 2, endAngle - Math.PI, !clockwise);

      if (r0 !== 0) {
        ctx.arc(x, y, r0, endAngle, startAngle, clockwise);
        ctx.moveTo(unitStartX * r0 + x, unitEndY * r0 + y);
      }

      ctx.closePath();
    };

    return SausagePath;
  }(Path);

  function isCoordinateSystemType(coordSys, type) {
    return coordSys.type === type;
  }

  var BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'borderWidth'];
  var BAR_BORDER_RADIUS_QUERY = ['itemStyle', 'borderRadius'];
  var _eventPos = [0, 0];
  var mathMax$3 = Math.max;
  var mathMin$3 = Math.min;

  function getClipArea(coord, data) {
    var coordSysClipArea;

    if (isCoordinateSystemType(coord, 'cartesian2d')) {
      coordSysClipArea = coord.getArea && coord.getArea();
      var baseAxis = coord.getBaseAxis();

      if (baseAxis.type !== 'category' || !baseAxis.onBand) {
        var expandWidth = data.getLayout('bandWidth');

        if (baseAxis.isHorizontal()) {
          coordSysClipArea.x -= expandWidth;
          coordSysClipArea.width += expandWidth * 2;
        } else {
          coordSysClipArea.y -= expandWidth;
          coordSysClipArea.height += expandWidth * 2;
        }
      }
    }

    return coordSysClipArea;
  }

  var BarView = function (_super) {
    __extends(BarView, _super);

    function BarView() {
      var _this = _super.call(this) || this;

      _this.type = BarView.type;
      _this._isFirstFrame = true;
      return _this;
    }

    BarView.prototype.render = function (seriesModel, ecModel, api, payload) {
      this._model = seriesModel;
      this.removeOnRenderedListener(api);

      this._updateDrawMode(seriesModel);

      var coordinateSystemType = seriesModel.get('coordinateSystem');
      var isReorder = payload && payload.type === 'changeAxisOrder';

      if (coordinateSystemType === 'cartesian2d' || coordinateSystemType === 'polar') {
        this._isLargeDraw ? this._renderLarge(seriesModel, ecModel, api) : this._renderNormal(seriesModel, ecModel, api, isReorder);
      } else if (true) {
        console.warn('Only cartesian2d and polar supported for bar.');
      }
    };

    BarView.prototype.incrementalPrepareRender = function (seriesModel) {
      this._clear();

      this._updateDrawMode(seriesModel);

      this._updateLargeClip(seriesModel);
    };

    BarView.prototype.incrementalRender = function (params, seriesModel) {
      this._incrementalRenderLarge(params, seriesModel);
    };

    BarView.prototype._updateDrawMode = function (seriesModel) {
      var isLargeDraw = seriesModel.pipelineContext.large;

      if (this._isLargeDraw == null || isLargeDraw !== this._isLargeDraw) {
        this._isLargeDraw = isLargeDraw;

        this._clear();
      }
    };

    BarView.prototype._renderNormal = function (seriesModel, ecModel, api, isReorder) {
      var _this = this;

      var group = this.group;
      var data = seriesModel.getData();
      var oldData = this._data;
      var coord = seriesModel.coordinateSystem;
      var baseAxis = coord.getBaseAxis();
      var isHorizontalOrRadial;

      if (coord.type === 'cartesian2d') {
        isHorizontalOrRadial = baseAxis.isHorizontal();
      } else if (coord.type === 'polar') {
        isHorizontalOrRadial = baseAxis.dim === 'angle';
      }

      var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;
      var axis2DModel = baseAxis.model;
      var realtimeSort = seriesModel.get('realtimeSort');

      if (realtimeSort && data.count()) {
        if (this._isFirstFrame) {
          this._initSort(data, isHorizontalOrRadial, baseAxis, api);

          this._isFirstFrame = false;
          return;
        } else {
          this._onRendered = function () {
            var orderMap = function (idx) {
              var el = data.getItemGraphicEl(idx);

              if (el) {
                var shape = el.shape;
                return (isHorizontalOrRadial ? shape.y + shape.height : shape.x + shape.width) || 0;
              } else {
                return 0;
              }
            };

            _this._updateSort(data, orderMap, baseAxis, api);
          };

          api.getZr().on('rendered', this._onRendered);
        }
      }

      var needsClip = seriesModel.get('clip', true) || realtimeSort;
      var coordSysClipArea = getClipArea(coord, data);
      group.removeClipPath();
      var roundCap = seriesModel.get('roundCap', true);
      var drawBackground = seriesModel.get('showBackground', true);
      var backgroundModel = seriesModel.getModel('backgroundStyle');
      var barBorderRadius = backgroundModel.get('borderRadius') || 0;
      var bgEls = [];
      var oldBgEls = this._backgroundEls;
      data.diff(oldData).add(function (dataIndex) {
        var itemModel = data.getItemModel(dataIndex);
        var layout = getLayout[coord.type](data, dataIndex, itemModel);

        if (drawBackground) {
          var bgLayout = getLayout[coord.type](data, dataIndex);
          var bgEl = createBackgroundEl(coord, isHorizontalOrRadial, bgLayout);
          bgEl.useStyle(backgroundModel.getItemStyle());

          if (coord.type === 'cartesian2d') {
            bgEl.setShape('r', barBorderRadius);
          }

          bgEls[dataIndex] = bgEl;
        }

        if (!data.hasValue(dataIndex)) {
          return;
        }

        var isClipped = false;

        if (needsClip) {
          isClipped = clip[coord.type](coordSysClipArea, layout);
        }

        var el = elementCreator[coord.type](seriesModel, data, dataIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, false, roundCap);
        updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar');

        if (realtimeSort) {
          el.disableLabelAnimation = true;
          updateRealtimeAnimation(seriesModel, axis2DModel, animationModel, el, layout, data, dataIndex, isHorizontalOrRadial, false);
        } else if (coord.type === 'cartesian2d') {
          initProps(el, {
            shape: layout
          }, seriesModel, dataIndex);
        }

        data.setItemGraphicEl(dataIndex, el);
        group.add(el);
        el.ignore = isClipped;
      }).update(function (newIndex, oldIndex) {
        var itemModel = data.getItemModel(newIndex);
        var layout = getLayout[coord.type](data, newIndex, itemModel);

        if (drawBackground) {
          var bgEl = oldBgEls[oldIndex];
          bgEl.useStyle(backgroundModel.getItemStyle());

          if (coord.type === 'cartesian2d') {
            bgEl.setShape('r', barBorderRadius);
          }

          bgEls[newIndex] = bgEl;
          var bgLayout = getLayout[coord.type](data, newIndex);
          var shape = createBackgroundShape(isHorizontalOrRadial, bgLayout, coord);
          updateProps(bgEl, {
            shape: shape
          }, animationModel, newIndex);
        }

        var el = oldData.getItemGraphicEl(oldIndex);

        if (!data.hasValue(newIndex)) {
          group.remove(el);
          el = null;
        }

        var isClipped = false;

        if (needsClip) {
          isClipped = clip[coord.type](coordSysClipArea, layout);

          if (isClipped) {
            group.remove(el);
          }
        }

        if (!el) {
          el = elementCreator[coord.type](seriesModel, data, newIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, !!el, roundCap);
        }

        updateStyle(el, data, newIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar');

        if (realtimeSort) {
          el.disableLabelAnimation = true;
          updateRealtimeAnimation(seriesModel, axis2DModel, animationModel, el, layout, data, newIndex, isHorizontalOrRadial, true);
        } else {
          updateProps(el, {
            shape: layout
          }, seriesModel, newIndex, null);
        }

        data.setItemGraphicEl(newIndex, el);
        el.ignore = isClipped;
        group.add(el);
      }).remove(function (dataIndex) {
        var el = oldData.getItemGraphicEl(dataIndex);
        el && removeElementWithFadeOut(el, seriesModel, dataIndex);
      }).execute();
      var bgGroup = this._backgroundGroup || (this._backgroundGroup = new Group());
      bgGroup.removeAll();

      for (var i = 0; i < bgEls.length; ++i) {
        bgGroup.add(bgEls[i]);
      }

      group.add(bgGroup);
      this._backgroundEls = bgEls;
      this._data = data;
    };

    BarView.prototype._renderLarge = function (seriesModel, ecModel, api) {
      this._clear();

      createLarge(seriesModel, this.group);

      this._updateLargeClip(seriesModel);
    };

    BarView.prototype._incrementalRenderLarge = function (params, seriesModel) {
      this._removeBackground();

      createLarge(seriesModel, this.group, true);
    };

    BarView.prototype._updateLargeClip = function (seriesModel) {
      var clipPath = seriesModel.get('clip', true) ? createClipPath(seriesModel.coordinateSystem, false, seriesModel) : null;

      if (clipPath) {
        this.group.setClipPath(clipPath);
      } else {
        this.group.removeClipPath();
      }
    };

    BarView.prototype._dataSort = function (data, idxMap) {
      var info = [];
      data.each(function (idx) {
        info.push({
          mappedValue: idxMap(idx),
          ordinalNumber: idx,
          beforeSortIndex: null
        });
      });
      info.sort(function (a, b) {
        return b.mappedValue - a.mappedValue;
      });

      for (var i = 0; i < info.length; ++i) {
        info[info[i].ordinalNumber].beforeSortIndex = i;
      }

      return map(info, function (item) {
        return {
          ordinalNumber: item.ordinalNumber,
          beforeSortIndex: item.beforeSortIndex
        };
      });
    };

    BarView.prototype._isDataOrderChanged = function (data, orderMap, oldOrder) {
      var oldCount = oldOrder ? oldOrder.length : 0;

      if (oldCount !== data.count()) {
        return true;
      }

      var lastValue = Number.MAX_VALUE;

      for (var i = 0; i < oldOrder.length; ++i) {
        var value = orderMap(oldOrder[i].ordinalNumber);

        if (value > lastValue) {
          return true;
        }

        lastValue = value;
      }

      return false;
    };

    BarView.prototype._updateSort = function (data, orderMap, baseAxis, api) {
      var oldOrder = baseAxis.scale.getCategorySortInfo();

      var isOrderChanged = this._isDataOrderChanged(data, orderMap, oldOrder);

      if (isOrderChanged) {
        var newOrder = this._dataSort(data, orderMap);

        var extent = baseAxis.scale.getExtent();

        for (var i = extent[0]; i < extent[1]; ++i) {
          if (!oldOrder[i] || oldOrder[i].ordinalNumber !== newOrder[i].ordinalNumber) {
            this.removeOnRenderedListener(api);
            var action = {
              type: 'changeAxisOrder',
              componentType: baseAxis.dim + 'Axis',
              axisId: baseAxis.index,
              sortInfo: newOrder
            };
            api.dispatchAction(action);
            break;
          }
        }
      }
    };

    BarView.prototype._initSort = function (data, isHorizontal, baseAxis, api) {
      var action = {
        type: 'changeAxisOrder',
        componentType: baseAxis.dim + 'Axis',
        axisId: baseAxis.index,
        sortInfo: this._dataSort(data, function (idx) {
          return parseFloat(data.get(isHorizontal ? 'y' : 'x', idx)) || 0;
        })
      };
      api.dispatchAction(action);
    };

    BarView.prototype.remove = function (ecModel, api) {
      this._clear(this._model);

      this.removeOnRenderedListener(api);
    };

    BarView.prototype.dispose = function (ecModel, api) {
      this.removeOnRenderedListener(api);
    };

    BarView.prototype.removeOnRenderedListener = function (api) {
      if (this._onRendered) {
        api.getZr().off('rendered', this._onRendered);
        this._onRendered = null;
      }
    };

    BarView.prototype._clear = function (model) {
      var group = this.group;
      var data = this._data;

      if (model && model.isAnimationEnabled() && data && !this._isLargeDraw) {
        this._removeBackground();

        this._backgroundEls = [];
        data.eachItemGraphicEl(function (el) {
          removeElementWithFadeOut(el, model, getECData(el).dataIndex);
        });
      } else {
        group.removeAll();
      }

      this._data = null;
      this._isFirstFrame = true;
    };

    BarView.prototype._removeBackground = function () {
      this.group.remove(this._backgroundGroup);
      this._backgroundGroup = null;
    };

    BarView.type = 'bar';
    return BarView;
  }(ChartView);

  var clip = {
    cartesian2d: function (coordSysBoundingRect, layout) {
      var signWidth = layout.width < 0 ? -1 : 1;
      var signHeight = layout.height < 0 ? -1 : 1;

      if (signWidth < 0) {
        layout.x += layout.width;
        layout.width = -layout.width;
      }

      if (signHeight < 0) {
        layout.y += layout.height;
        layout.height = -layout.height;
      }

      var x = mathMax$3(layout.x, coordSysBoundingRect.x);
      var x2 = mathMin$3(layout.x + layout.width, coordSysBoundingRect.x + coordSysBoundingRect.width);
      var y = mathMax$3(layout.y, coordSysBoundingRect.y);
      var y2 = mathMin$3(layout.y + layout.height, coordSysBoundingRect.y + coordSysBoundingRect.height);
      layout.x = x;
      layout.y = y;
      layout.width = x2 - x;
      layout.height = y2 - y;
      var clipped = layout.width < 0 || layout.height < 0;

      if (signWidth < 0) {
        layout.x += layout.width;
        layout.width = -layout.width;
      }

      if (signHeight < 0) {
        layout.y += layout.height;
        layout.height = -layout.height;
      }

      return clipped;
    },
    polar: function () {
      return false;
    }
  };
  var elementCreator = {
    cartesian2d: function (seriesModel, data, newIndex, layout, isHorizontal, animationModel, axisModel, isUpdate, roundCap) {
      var rect = new Rect({
        shape: extend({}, layout),
        z2: 1
      });
      rect.__dataIndex = newIndex;
      rect.name = 'item';

      if (animationModel) {
        var rectShape = rect.shape;
        var animateProperty = isHorizontal ? 'height' : 'width';
        rectShape[animateProperty] = 0;
      }

      return rect;
    },
    polar: function (seriesModel, data, newIndex, layout, isRadial, animationModel, axisModel, isUpdate, roundCap) {
      var clockwise = layout.startAngle < layout.endAngle;
      var ShapeClass = !isRadial && roundCap ? SausagePath : Sector;
      var sector = new ShapeClass({
        shape: defaults({
          clockwise: clockwise
        }, layout),
        z2: 1
      });
      sector.name = 'item';

      if (animationModel) {
        var sectorShape = sector.shape;
        var animateProperty = isRadial ? 'r' : 'endAngle';
        var animateTarget = {};
        sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;
        animateTarget[animateProperty] = layout[animateProperty];
        (isUpdate ? updateProps : initProps)(sector, {
          shape: animateTarget
        }, animationModel);
      }

      return sector;
    }
  };

  function updateRealtimeAnimation(seriesModel, axisModel, animationModel, el, layout, data, newIndex, isHorizontal, isUpdate) {
    if (animationModel || axisModel) {
      var seriesTarget = void 0;
      var axisTarget = void 0;

      if (isHorizontal) {
        axisTarget = {
          x: layout.x,
          width: layout.width
        };
        seriesTarget = {
          y: layout.y,
          height: layout.height
        };
      } else {
        axisTarget = {
          y: layout.y,
          height: layout.height
        };
        seriesTarget = {
          x: layout.x,
          width: layout.width
        };
      }

      (isUpdate ? updateProps : initProps)(el, {
        shape: seriesTarget
      }, seriesModel, newIndex, null);
      (isUpdate ? updateProps : initProps)(el, {
        shape: axisTarget
      }, axisModel, newIndex);

      var defaultTextGetter = function (values) {
        return getDefaultLabel(seriesModel.getData(), newIndex, values);
      };

      var labelModel = seriesModel.getModel('label');
      (isUpdate ? updateLabel : initLabel)(el, data, newIndex, labelModel, seriesModel, animationModel, defaultTextGetter);
    }
  }

  var getLayout = {
    cartesian2d: function (data, dataIndex, itemModel) {
      var layout = data.getItemLayout(dataIndex);
      var fixedLineWidth = itemModel ? getLineWidth(itemModel, layout) : 0;
      var signX = layout.width > 0 ? 1 : -1;
      var signY = layout.height > 0 ? 1 : -1;
      return {
        x: layout.x + signX * fixedLineWidth / 2,
        y: layout.y + signY * fixedLineWidth / 2,
        width: layout.width - signX * fixedLineWidth,
        height: layout.height - signY * fixedLineWidth
      };
    },
    polar: function (data, dataIndex, itemModel) {
      var layout = data.getItemLayout(dataIndex);
      return {
        cx: layout.cx,
        cy: layout.cy,
        r0: layout.r0,
        r: layout.r,
        startAngle: layout.startAngle,
        endAngle: layout.endAngle
      };
    }
  };

  function isZeroOnPolar(layout) {
    return layout.startAngle != null && layout.endAngle != null && layout.startAngle === layout.endAngle;
  }

  function updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar) {
    var style = data.getItemVisual(dataIndex, 'style');

    if (!isPolar) {
      el.setShape('r', itemModel.get(BAR_BORDER_RADIUS_QUERY) || 0);
    }

    el.useStyle(style);
    el.ignore = isZeroOnPolar(layout);
    var cursorStyle = itemModel.getShallow('cursor');
    cursorStyle && el.attr('cursor', cursorStyle);

    if (!isPolar) {
      var labelPositionOutside = isHorizontal ? layout.height > 0 ? 'bottom' : 'top' : layout.width > 0 ? 'left' : 'right';
      setLabelStyle(el, getLabelStatesModels(itemModel), {
        labelFetcher: seriesModel,
        labelDataIndex: dataIndex,
        defaultText: getDefaultLabel(seriesModel.getData(), dataIndex),
        inheritColor: style.fill,
        defaultOutsidePosition: labelPositionOutside
      });
    }

    var emphasisModel = itemModel.getModel(['emphasis']);
    enableHoverEmphasis(el, emphasisModel.get('focus'), emphasisModel.get('blurScope'));
    setStatesStylesFromModel(el, itemModel);

    if (isZeroOnPolar(layout)) {
      each(el.states, function (state) {
        if (state.style) {
          state.style.fill = state.style.stroke = 'none';
        }
      });
    }
  }

  function getLineWidth(itemModel, rawLayout) {
    var lineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0;
    var width = isNaN(rawLayout.width) ? Number.MAX_VALUE : Math.abs(rawLayout.width);
    var height = isNaN(rawLayout.height) ? Number.MAX_VALUE : Math.abs(rawLayout.height);
    return Math.min(lineWidth, width, height);
  }

  var LagePathShape = function () {
    function LagePathShape() {}

    return LagePathShape;
  }();

  var LargePath = function (_super) {
    __extends(LargePath, _super);

    function LargePath(opts) {
      var _this = _super.call(this, opts) || this;

      _this.type = 'largeBar';
      return _this;
    }

    LargePath.prototype.getDefaultShape = function () {
      return new LagePathShape();
    };

    LargePath.prototype.buildPath = function (ctx, shape) {
      var points = shape.points;
      var startPoint = this.__startPoint;
      var baseDimIdx = this.__baseDimIdx;

      for (var i = 0; i < points.length; i += 2) {
        startPoint[baseDimIdx] = points[i + baseDimIdx];
        ctx.moveTo(startPoint[0], startPoint[1]);
        ctx.lineTo(points[i], points[i + 1]);
      }
    };

    return LargePath;
  }(Path);

  function createLarge(seriesModel, group, incremental) {
    var data = seriesModel.getData();
    var startPoint = [];
    var baseDimIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0;
    startPoint[1 - baseDimIdx] = data.getLayout('valueAxisStart');
    var largeDataIndices = data.getLayout('largeDataIndices');
    var barWidth = data.getLayout('barWidth');
    var backgroundModel = seriesModel.getModel('backgroundStyle');
    var drawBackground = seriesModel.get('showBackground', true);

    if (drawBackground) {
      var points = data.getLayout('largeBackgroundPoints');
      var backgroundStartPoint = [];
      backgroundStartPoint[1 - baseDimIdx] = data.getLayout('backgroundStart');
      var bgEl = new LargePath({
        shape: {
          points: points
        },
        incremental: !!incremental,
        silent: true,
        z2: 0
      });
      bgEl.__startPoint = backgroundStartPoint;
      bgEl.__baseDimIdx = baseDimIdx;
      bgEl.__largeDataIndices = largeDataIndices;
      bgEl.__barWidth = barWidth;
      setLargeBackgroundStyle(bgEl, backgroundModel, data);
      group.add(bgEl);
    }

    var el = new LargePath({
      shape: {
        points: data.getLayout('largePoints')
      },
      incremental: !!incremental
    });
    el.__startPoint = startPoint;
    el.__baseDimIdx = baseDimIdx;
    el.__largeDataIndices = largeDataIndices;
    el.__barWidth = barWidth;
    group.add(el);
    setLargeStyle(el, seriesModel, data);
    getECData(el).seriesIndex = seriesModel.seriesIndex;

    if (!seriesModel.get('silent')) {
      el.on('mousedown', largePathUpdateDataIndex);
      el.on('mousemove', largePathUpdateDataIndex);
    }
  }

  var largePathUpdateDataIndex = throttle(function (event) {
    var largePath = this;
    var dataIndex = largePathFindDataIndex(largePath, event.offsetX, event.offsetY);
    getECData(largePath).dataIndex = dataIndex >= 0 ? dataIndex : null;
  }, 30, false);

  function largePathFindDataIndex(largePath, x, y) {
    var baseDimIdx = largePath.__baseDimIdx;
    var valueDimIdx = 1 - baseDimIdx;
    var points = largePath.shape.points;
    var largeDataIndices = largePath.__largeDataIndices;
    var barWidthHalf = Math.abs(largePath.__barWidth / 2);
    var startValueVal = largePath.__startPoint[valueDimIdx];
    _eventPos[0] = x;
    _eventPos[1] = y;
    var pointerBaseVal = _eventPos[baseDimIdx];
    var pointerValueVal = _eventPos[1 - baseDimIdx];
    var baseLowerBound = pointerBaseVal - barWidthHalf;
    var baseUpperBound = pointerBaseVal + barWidthHalf;

    for (var i = 0, len = points.length / 2; i < len; i++) {
      var ii = i * 2;
      var barBaseVal = points[ii + baseDimIdx];
      var barValueVal = points[ii + valueDimIdx];

      if (barBaseVal >= baseLowerBound && barBaseVal <= baseUpperBound && (startValueVal <= barValueVal ? pointerValueVal >= startValueVal && pointerValueVal <= barValueVal : pointerValueVal >= barValueVal && pointerValueVal <= startValueVal)) {
        return largeDataIndices[i];
      }
    }

    return -1;
  }

  function setLargeStyle(el, seriesModel, data) {
    var globalStyle = data.getVisual('style');
    el.useStyle(extend({}, globalStyle));
    el.style.fill = null;
    el.style.stroke = globalStyle.fill;
    el.style.lineWidth = data.getLayout('barWidth');
  }

  function setLargeBackgroundStyle(el, backgroundModel, data) {
    var borderColor = backgroundModel.get('borderColor') || backgroundModel.get('color');
    var itemStyle = backgroundModel.getItemStyle();
    el.useStyle(itemStyle);
    el.style.fill = null;
    el.style.stroke = borderColor;
    el.style.lineWidth = data.getLayout('barWidth');
  }

  function createBackgroundShape(isHorizontalOrRadial, layout, coord) {
    if (isCoordinateSystemType(coord, 'cartesian2d')) {
      var rectShape = layout;
      var coordLayout = coord.getArea();
      return {
        x: isHorizontalOrRadial ? rectShape.x : coordLayout.x,
        y: isHorizontalOrRadial ? coordLayout.y : rectShape.y,
        width: isHorizontalOrRadial ? rectShape.width : coordLayout.width,
        height: isHorizontalOrRadial ? coordLayout.height : rectShape.height
      };
    } else {
      var coordLayout = coord.getArea();
      var sectorShape = layout;
      return {
        cx: coordLayout.cx,
        cy: coordLayout.cy,
        r0: isHorizontalOrRadial ? coordLayout.r0 : sectorShape.r0,
        r: isHorizontalOrRadial ? coordLayout.r : sectorShape.r,
        startAngle: isHorizontalOrRadial ? sectorShape.startAngle : 0,
        endAngle: isHorizontalOrRadial ? sectorShape.endAngle : Math.PI * 2
      };
    }
  }

  function createBackgroundEl(coord, isHorizontalOrRadial, layout) {
    var ElementClz = coord.type === 'polar' ? Sector : Rect;
    return new ElementClz({
      shape: createBackgroundShape(isHorizontalOrRadial, layout, coord),
      silent: true,
      z2: 0
    });
  }

  ChartView.registerClass(BarView);
  registerAction({
    type: 'changeAxisOrder',
    event: 'changeAxisOrder',
    update: 'update'
  }, function (payload, ecModel) {
    var componentType = payload.componentType || 'series';
    ecModel.eachComponent({
      mainType: componentType,
      query: payload
    }, function (componentModel) {
      if (payload.sortInfo) {
        componentModel.axis.setCategorySortInfo(payload.sortInfo);
      }
    });
  });
  registerLayout(PRIORITY.VISUAL.LAYOUT, curry(layout, 'bar'));
  registerLayout(PRIORITY.VISUAL.PROGRESSIVE_LAYOUT, largeLayout);
  registerVisual({
    seriesType: 'bar',
    reset: function (seriesModel) {
      seriesModel.getData().setVisual('legendSymbol', 'roundRect');
    }
  });

  function createListSimply(seriesModel, opt, nameList) {
    opt = isArray(opt) && {
      coordDimensions: opt
    } || extend({}, opt);
    var source = seriesModel.getSource();
    var dimensionsInfo = createDimensions(source, opt);
    var list = new List(dimensionsInfo, seriesModel);
    list.initData(source, nameList);
    return list;
  }

  var LegendVisualProvider = function () {
    function LegendVisualProvider(getDataWithEncodedVisual, getRawData) {
      this._getDataWithEncodedVisual = getDataWithEncodedVisual;
      this._getRawData = getRawData;
    }

    LegendVisualProvider.prototype.getAllNames = function () {
      var rawData = this._getRawData();

      return rawData.mapArray(rawData.getName);
    };

    LegendVisualProvider.prototype.containName = function (name) {
      var rawData = this._getRawData();

      return rawData.indexOfName(name) >= 0;
    };

    LegendVisualProvider.prototype.indexOfName = function (name) {
      var dataWithEncodedVisual = this._getDataWithEncodedVisual();

      return dataWithEncodedVisual.indexOfName(name);
    };

    LegendVisualProvider.prototype.getItemVisual = function (dataIndex, key) {
      var dataWithEncodedVisual = this._getDataWithEncodedVisual();

      return dataWithEncodedVisual.getItemVisual(dataIndex, key);
    };

    return LegendVisualProvider;
  }();

  var PieSeriesModel = function (_super) {
    __extends(PieSeriesModel, _super);

    function PieSeriesModel() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.useColorPaletteOnData = true;
      return _this;
    }

    PieSeriesModel.prototype.init = function (option) {
      _super.prototype.init.apply(this, arguments);

      this.legendVisualProvider = new LegendVisualProvider(bind(this.getData, this), bind(this.getRawData, this));

      this._defaultLabelLine(option);
    };

    PieSeriesModel.prototype.mergeOption = function () {
      _super.prototype.mergeOption.apply(this, arguments);
    };

    PieSeriesModel.prototype.getInitialData = function () {
      return createListSimply(this, {
        coordDimensions: ['value'],
        encodeDefaulter: curry(makeSeriesEncodeForNameBased, this)
      });
    };

    PieSeriesModel.prototype.getDataParams = function (dataIndex) {
      var data = this.getData();

      var params = _super.prototype.getDataParams.call(this, dataIndex);

      var valueList = [];
      data.each(data.mapDimension('value'), function (value) {
        valueList.push(value);
      });
      params.percent = getPercentWithPrecision(valueList, dataIndex, data.hostModel.get('percentPrecision'));
      params.$vars.push('percent');
      return params;
    };

    PieSeriesModel.prototype._defaultLabelLine = function (option) {
      defaultEmphasis(option, 'labelLine', ['show']);
      var labelLineNormalOpt = option.labelLine;
      var labelLineEmphasisOpt = option.emphasis.labelLine;
      labelLineNormalOpt.show = labelLineNormalOpt.show && option.label.show;
      labelLineEmphasisOpt.show = labelLineEmphasisOpt.show && option.emphasis.label.show;
    };

    PieSeriesModel.type = 'series.pie';
    PieSeriesModel.defaultOption = {
      zlevel: 0,
      z: 2,
      legendHoverLink: true,
      center: ['50%', '50%'],
      radius: [0, '75%'],
      clockwise: true,
      startAngle: 90,
      minAngle: 0,
      minShowLabelAngle: 0,
      selectedOffset: 10,
      percentPrecision: 2,
      stillShowZeroSum: true,
      left: 0,
      top: 0,
      right: 0,
      bottom: 0,
      width: null,
      height: null,
      label: {
        rotate: 0,
        show: true,
        overflow: 'truncate',
        position: 'outer',
        alignTo: 'none',
        edgeDistance: '25%',
        bleedMargin: 10,
        distanceToLabelLine: 5
      },
      labelLine: {
        show: true,
        length: 15,
        length2: 15,
        smooth: false,
        minTurnAngle: 90,
        maxSurfaceAngle: 90,
        lineStyle: {
          width: 1,
          type: 'solid'
        }
      },
      itemStyle: {
        borderWidth: 1
      },
      labelLayout: {
        hideOverlap: true
      },
      emphasis: {
        scale: true,
        scaleSize: 5
      },
      avoidLabelOverlap: true,
      animationType: 'expansion',
      animationDuration: 1000,
      animationTypeUpdate: 'transition',
      animationEasingUpdate: 'cubicInOut',
      animationDurationUpdate: 500,
      animationEasing: 'cubicInOut'
    };
    return PieSeriesModel;
  }(SeriesModel);

  SeriesModel.registerClass(PieSeriesModel);
  var RADIAN = Math.PI / 180;

  function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight, viewLeft, viewTop, farthestX) {
    if (list.length < 2) {
      return;
    }

    function recalculateXOnSemiToAlignOnEllipseCurve(semi) {
      var rB = semi.rB;
      var rB2 = rB * rB;

      for (var i = 0; i < semi.list.length; i++) {
        var item = semi.list[i];
        var dy = Math.abs(item.label.y - cy);
        var rA = r + item.len;
        var rA2 = rA * rA;
        var dx = Math.sqrt((1 - Math.abs(dy * dy / rB2)) * rA2);
        item.label.x = cx + (dx + item.len2) * dir;
      }
    }

    function recalculateX(items) {
      var topSemi = {
        list: [],
        maxY: 0
      };
      var bottomSemi = {
        list: [],
        maxY: 0
      };

      for (var i = 0; i < items.length; i++) {
        if (items[i].labelAlignTo !== 'none') {
          continue;
        }

        var item = items[i];
        var semi = item.label.y > cy ? bottomSemi : topSemi;
        var dy = Math.abs(item.label.y - cy);

        if (dy > semi.maxY) {
          var dx = item.label.x - cx - item.len2 * dir;
          var rA = r + item.len;
          var rB = dx < rA ? Math.sqrt(dy * dy / (1 - dx * dx / rA / rA)) : rA;
          semi.rB = rB;
          semi.maxY = dy;
        }

        semi.list.push(item);
      }

      recalculateXOnSemiToAlignOnEllipseCurve(topSemi);
      recalculateXOnSemiToAlignOnEllipseCurve(bottomSemi);
    }

    var len = list.length;

    for (var i = 0; i < len; i++) {
      if (list[i].position === 'outer' && list[i].labelAlignTo === 'labelLine') {
        var dx = list[i].label.x - farthestX;
        list[i].linePoints[1][0] += dx;
        list[i].label.x = farthestX;
      }
    }

    if (shiftLayoutOnY(list, viewTop, viewTop + viewHeight)) {
      recalculateX(list);
    }
  }

  function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop) {
    var leftList = [];
    var rightList = [];
    var leftmostX = Number.MAX_VALUE;
    var rightmostX = -Number.MAX_VALUE;

    for (var i = 0; i < labelLayoutList.length; i++) {
      var label = labelLayoutList[i].label;

      if (isPositionCenter(labelLayoutList[i])) {
        continue;
      }

      if (label.x < cx) {
        leftmostX = Math.min(leftmostX, label.x);
        leftList.push(labelLayoutList[i]);
      } else {
        rightmostX = Math.max(rightmostX, label.x);
        rightList.push(labelLayoutList[i]);
      }
    }

    adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight, viewLeft, viewTop, rightmostX);
    adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight, viewLeft, viewTop, leftmostX);

    for (var i = 0; i < labelLayoutList.length; i++) {
      var layout = labelLayoutList[i];
      var label = layout.label;

      if (isPositionCenter(layout)) {
        continue;
      }

      var linePoints = layout.linePoints;

      if (linePoints) {
        var isAlignToEdge = layout.labelAlignTo === 'edge';
        var realTextWidth = layout.rect.width;
        var targetTextWidth = void 0;

        if (isAlignToEdge) {
          if (label.x < cx) {
            targetTextWidth = linePoints[2][0] - layout.labelDistance - viewLeft - layout.edgeDistance;
          } else {
            targetTextWidth = viewLeft + viewWidth - layout.edgeDistance - linePoints[2][0] - layout.labelDistance;
          }
        } else {
          if (label.x < cx) {
            targetTextWidth = label.x - viewLeft - layout.bleedMargin;
          } else {
            targetTextWidth = viewLeft + viewWidth - label.x - layout.bleedMargin;
          }
        }

        if (targetTextWidth < layout.rect.width) {
          layout.label.style.width = targetTextWidth;

          if (layout.labelAlignTo === 'edge') {
            realTextWidth = targetTextWidth;
          }
        }

        var dist = linePoints[1][0] - linePoints[2][0];

        if (isAlignToEdge) {
          if (label.x < cx) {
            linePoints[2][0] = viewLeft + layout.edgeDistance + realTextWidth + layout.labelDistance;
          } else {
            linePoints[2][0] = viewLeft + viewWidth - layout.edgeDistance - realTextWidth - layout.labelDistance;
          }
        } else {
          if (label.x < cx) {
            linePoints[2][0] = label.x + layout.labelDistance;
          } else {
            linePoints[2][0] = label.x - layout.labelDistance;
          }

          linePoints[1][0] = linePoints[2][0] + dist;
        }

        linePoints[1][1] = linePoints[2][1] = label.y;
      }
    }
  }

  function isPositionCenter(sectorShape) {
    return sectorShape.position === 'center';
  }

  function labelLayout(seriesModel) {
    var data = seriesModel.getData();
    var labelLayoutList = [];
    var cx;
    var cy;
    var hasLabelRotate = false;
    var minShowLabelRadian = (seriesModel.get('minShowLabelAngle') || 0) * RADIAN;
    var viewRect = data.getLayout('viewRect');
    var r = data.getLayout('r');
    var viewWidth = viewRect.width;
    var viewLeft = viewRect.x;
    var viewTop = viewRect.y;
    var viewHeight = viewRect.height;

    function setNotShow(el) {
      el.ignore = true;
    }

    data.each(function (idx) {
      var sector = data.getItemGraphicEl(idx);
      var sectorShape = sector.shape;
      var label = sector.getTextContent();
      var labelLine = sector.getTextGuideLine();
      var itemModel = data.getItemModel(idx);
      var labelModel = itemModel.getModel('label');
      var labelPosition = labelModel.get('position') || itemModel.get(['emphasis', 'label', 'position']);
      var labelDistance = labelModel.get('distanceToLabelLine');
      var labelAlignTo = labelModel.get('alignTo');
      var edgeDistance = parsePercent$2(labelModel.get('edgeDistance'), viewWidth);
      var bleedMargin = labelModel.get('bleedMargin');
      var labelLineModel = itemModel.getModel('labelLine');
      var labelLineLen = labelLineModel.get('length');
      labelLineLen = parsePercent$2(labelLineLen, viewWidth);
      var labelLineLen2 = labelLineModel.get('length2');
      labelLineLen2 = parsePercent$2(labelLineLen2, viewWidth);

      if (Math.abs(sectorShape.endAngle - sectorShape.startAngle) < minShowLabelRadian) {
        each(label.states, setNotShow);
        label.ignore = true;
        return;
      }

      var midAngle = (sectorShape.startAngle + sectorShape.endAngle) / 2;
      var nx = Math.cos(midAngle);
      var ny = Math.sin(midAngle);
      var textX;
      var textY;
      var linePoints;
      var textAlign;
      cx = sectorShape.cx;
      cy = sectorShape.cy;
      var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';

      if (labelPosition === 'center') {
        textX = sectorShape.cx;
        textY = sectorShape.cy;
        textAlign = 'center';
      } else {
        var x1 = (isLabelInside ? (sectorShape.r + sectorShape.r0) / 2 * nx : sectorShape.r * nx) + cx;
        var y1 = (isLabelInside ? (sectorShape.r + sectorShape.r0) / 2 * ny : sectorShape.r * ny) + cy;
        textX = x1 + nx * 3;
        textY = y1 + ny * 3;

        if (!isLabelInside) {
          var x2 = x1 + nx * (labelLineLen + r - sectorShape.r);
          var y2 = y1 + ny * (labelLineLen + r - sectorShape.r);
          var x3 = x2 + (nx < 0 ? -1 : 1) * labelLineLen2;
          var y3 = y2;

          if (labelAlignTo === 'edge') {
            textX = nx < 0 ? viewLeft + edgeDistance : viewLeft + viewWidth - edgeDistance;
          } else {
            textX = x3 + (nx < 0 ? -labelDistance : labelDistance);
          }

          textY = y3;
          linePoints = [[x1, y1], [x2, y2], [x3, y3]];
        }

        textAlign = isLabelInside ? 'center' : labelAlignTo === 'edge' ? nx > 0 ? 'right' : 'left' : nx > 0 ? 'left' : 'right';
      }

      var labelRotate;
      var rotate = labelModel.get('rotate');

      if (typeof rotate === 'number') {
        labelRotate = rotate * (Math.PI / 180);
      } else {
        labelRotate = rotate ? nx < 0 ? -midAngle + Math.PI : -midAngle : 0;
      }

      hasLabelRotate = !!labelRotate;
      label.x = textX;
      label.y = textY;
      label.rotation = labelRotate;
      label.setStyle({
        verticalAlign: 'middle'
      });

      if (!isLabelInside) {
        var textRect = label.getBoundingRect().clone();
        textRect.applyTransform(label.getComputedTransform());
        var margin = (label.style.margin || 0) + 2.1;
        textRect.x -= margin / 2;
        textRect.y -= margin / 2;
        textRect.width += margin;
        textRect.height += margin;
        labelLayoutList.push({
          label: label,
          labelLine: labelLine,
          position: labelPosition,
          len: labelLineLen,
          len2: labelLineLen2,
          minTurnAngle: labelLineModel.get('minTurnAngle'),
          maxSurfaceAngle: labelLineModel.get('maxSurfaceAngle'),
          surfaceNormal: new Point(nx, ny),
          linePoints: linePoints,
          textAlign: textAlign,
          labelDistance: labelDistance,
          labelAlignTo: labelAlignTo,
          edgeDistance: edgeDistance,
          bleedMargin: bleedMargin,
          rect: textRect
        });
      } else {
        label.setStyle({
          align: textAlign
        });
        var selectState = label.states.select;

        if (selectState) {
          selectState.x += label.x;
          selectState.y += label.y;
        }
      }

      sector.setTextConfig({
        inside: isLabelInside
      });
    });

    if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {
      avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop);
    }

    for (var i = 0; i < labelLayoutList.length; i++) {
      var layout = labelLayoutList[i];
      var label = layout.label;
      var labelLine = layout.labelLine;
      var notShowLabel = isNaN(label.x) || isNaN(label.y);

      if (label) {
        label.setStyle({
          align: layout.textAlign
        });

        if (notShowLabel) {
          each(label.states, setNotShow);
          label.ignore = true;
        }

        var selectState = label.states.select;

        if (selectState) {
          selectState.x += label.x;
          selectState.y += label.y;
        }
      }

      if (labelLine) {
        var linePoints = layout.linePoints;

        if (notShowLabel || !linePoints) {
          each(labelLine.states, setNotShow);
          labelLine.ignore = true;
        } else {
          limitTurnAngle(linePoints, layout.minTurnAngle);
          limitSurfaceAngle(linePoints, layout.surfaceNormal, layout.maxSurfaceAngle);
          labelLine.setShape({
            points: linePoints
          });
          label.__hostTarget.textGuideLineConfig = {
            anchor: new Point(linePoints[0][0], linePoints[0][1])
          };
        }
      }
    }
  }

  var PiePiece = function (_super) {
    __extends(PiePiece, _super);

    function PiePiece(data, idx, startAngle) {
      var _this = _super.call(this) || this;

      _this.z2 = 2;
      var polyline = new Polyline();
      var text = new ZRText();

      _this.setTextGuideLine(polyline);

      _this.setTextContent(text);

      _this.updateData(data, idx, startAngle, true);

      return _this;
    }

    PiePiece.prototype.updateData = function (data, idx, startAngle, firstCreate) {
      var sector = this;
      var seriesModel = data.hostModel;
      var itemModel = data.getItemModel(idx);
      var emphasisModel = itemModel.getModel('emphasis');
      var layout = data.getItemLayout(idx);
      var sectorShape = extend({}, layout);

      if (firstCreate) {
        sector.setShape(sectorShape);
        var animationType = seriesModel.getShallow('animationType');

        if (animationType === 'scale') {
          sector.shape.r = layout.r0;
          initProps(sector, {
            shape: {
              r: layout.r
            }
          }, seriesModel, idx);
        } else {
          if (startAngle != null) {
            sector.setShape({
              startAngle: startAngle,
              endAngle: startAngle
            });
            initProps(sector, {
              shape: {
                startAngle: layout.startAngle,
                endAngle: layout.endAngle
              }
            }, seriesModel, idx);
          } else {
            sector.shape.endAngle = layout.startAngle;
            updateProps(sector, {
              shape: {
                endAngle: layout.endAngle
              }
            }, seriesModel, idx);
          }
        }
      } else {
        updateProps(sector, {
          shape: sectorShape
        }, seriesModel, idx);
      }

      sector.useStyle(data.getItemVisual(idx, 'style'));
      setStatesStylesFromModel(sector, itemModel);
      var midAngle = (layout.startAngle + layout.endAngle) / 2;
      var offset = seriesModel.get('selectedOffset');
      var dx = Math.cos(midAngle) * offset;
      var dy = Math.sin(midAngle) * offset;
      var cursorStyle = itemModel.getShallow('cursor');
      cursorStyle && sector.attr('cursor', cursorStyle);

      this._updateLabel(seriesModel, data, idx);

      sector.ensureState('emphasis').shape = {
        r: layout.r + (emphasisModel.get('scale') ? emphasisModel.get('scaleSize') || 0 : 0)
      };
      extend(sector.ensureState('select'), {
        x: dx,
        y: dy
      });
      var labelLine = sector.getTextGuideLine();
      var labelText = sector.getTextContent();
      extend(labelLine.ensureState('select'), {
        x: dx,
        y: dy
      });
      extend(labelText.ensureState('select'), {
        x: dx,
        y: dy
      });
      enableHoverEmphasis(this, emphasisModel.get('focus'), emphasisModel.get('blurScope'));
    };

    PiePiece.prototype._updateLabel = function (seriesModel, data, idx) {
      var sector = this;
      var labelText = sector.getTextContent();
      var itemModel = data.getItemModel(idx);
      var labelTextEmphasisState = labelText.ensureState('emphasis');
      var labelModel = itemModel.getModel('label');
      var labelHoverModel = itemModel.getModel(['emphasis', 'label']);
      var style = data.getItemVisual(idx, 'style');
      var visualColor = style && style.fill;
      setLabelStyle(sector, getLabelStatesModels(itemModel), {
        labelFetcher: data.hostModel,
        labelDataIndex: idx,
        inheritColor: visualColor,
        defaultText: seriesModel.getFormattedLabel(idx, 'normal') || data.getName(idx)
      }, {
        normal: {
          opacity: style && style.opacity
        }
      });
      sector.setTextConfig({
        position: null,
        rotation: null
      });
      labelText.attr({
        z2: 10
      });
      labelText.ignore = !labelModel.get('show');
      labelTextEmphasisState.ignore = !labelHoverModel.get('show');
      setLabelLineStyle(this, getLabelLineStatesModels(itemModel), {
        stroke: visualColor,
        opacity: style && style.opacity
      });
    };

    return PiePiece;
  }(Sector);

  var PieView = function (_super) {
    __extends(PieView, _super);

    function PieView() {
      var _this = _super !== null && _super.apply(this, arguments) || this;

      _this.ignoreLabelLineUpdate = true;
      return _this;
    }

    PieView.prototype.init = function () {
      var sectorGroup = new Group();
      this._sectorGroup = sectorGroup;
    };

    PieView.prototype.render = function (seriesModel, ecModel, api, payload) {
      var data = seriesModel.getData();
      var oldData = this._data;
      var group = this.group;
      var startAngle;

      if (!oldData && data.count() > 0) {
        var shape = data.getItemLayout(0);

        for (var s = 1; isNaN(shape && shape.startAngle) && s < data.count(); ++s) {
          shape = data.getItemLayout(s);
        }

        if (shape) {
          startAngle = shape.startAngle;
        }
      }

      data.diff(oldData).add(function (idx) {
        var piePiece = new PiePiece(data, idx, startAngle);
        data.setItemGraphicEl(idx, piePiece);
        group.add(piePiece);
      }).update(function (newIdx, oldIdx) {
        var piePiece = oldData.getItemGraphicEl(oldIdx);
        piePiece.updateData(data, newIdx, startAngle);
        piePiece.off('click');
        group.add(piePiece);
        data.setItemGraphicEl(newIdx, piePiece);
      }).remove(function (idx) {
        var piePiece = oldData.getItemGraphicEl(idx);
        removeElementWithFadeOut(piePiece, seriesModel, idx);
      }).execute();
      labelLayout(seriesModel);

      if (seriesModel.get('animationTypeUpdate') !== 'expansion') {
        this._data = data;
      }
    };

    PieView.prototype.dispose = function () {};

    PieView.prototype.containPoint = function (point, seriesModel) {
      var data = seriesModel.getData();
      var itemLayout = data.getItemLayout(0);

      if (itemLayout) {
        var dx = point[0] - itemLayout.cx;
        var dy = point[1] - itemLayout.cy;
        var radius = Math.sqrt(dx * dx + dy * dy);
        return radius <= itemLayout.r && radius >= itemLayout.r0;
      }
    };

    PieView.type = 'pie';
    return PieView;
  }(ChartView);

  ChartView.registerClass(PieView);
  var PI2$6 = Math.PI * 2;
  var RADIAN$1 = Math.PI / 180;

  function getViewRect(seriesModel, api) {
    return getLayoutRect(seriesModel.getBoxLayoutParams(), {
      width: api.getWidth(),
      height: api.getHeight()
    });
  }

  function pieLayout(seriesType, ecModel, api) {
    ecModel.eachSeriesByType(seriesType, function (seriesModel) {
      var data = seriesModel.getData();
      var valueDim = data.mapDimension('value');
      var viewRect = getViewRect(seriesModel, api);
      var center = seriesModel.get('center');
      var radius = seriesModel.get('radius');

      if (!isArray(radius)) {
        radius = [0, radius];
      }

      if (!isArray(center)) {
        center = [center, center];
      }

      var width = parsePercent$2(viewRect.width, api.getWidth());
      var height = parsePercent$2(viewRect.height, api.getHeight());
      var size = Math.min(width, height);
      var cx = parsePercent$2(center[0], width) + viewRect.x;
      var cy = parsePercent$2(center[1], height) + viewRect.y;
      var r0 = parsePercent$2(radius[0], size / 2);
      var r = parsePercent$2(radius[1], size / 2);
      var startAngle = -seriesModel.get('startAngle') * RADIAN$1;
      var minAngle = seriesModel.get('minAngle') * RADIAN$1;
      var validDataCount = 0;
      data.each(valueDim, function (value) {
        !isNaN(value) && validDataCount++;
      });
      var sum = data.getSum(valueDim);
      var unitRadian = Math.PI / (sum || validDataCount) * 2;
      var clockwise = seriesModel.get('clockwise');
      var roseType = seriesModel.get('roseType');
      var stillShowZeroSum = seriesModel.get('stillShowZeroSum');
      var extent = data.getDataExtent(valueDim);
      extent[0] = 0;
      var restAngle = PI2$6;
      var valueSumLargerThanMinAngle = 0;
      var currentAngle = startAngle;
      var dir = clockwise ? 1 : -1;
      data.setLayout({
        viewRect: viewRect,
        r: r
      });
      data.each(valueDim, function (value, idx) {
        var angle;

        if (isNaN(value)) {
          data.setItemLayout(idx, {
            angle: NaN,
            startAngle: NaN,
            endAngle: NaN,
            clockwise: clockwise,
            cx: cx,
            cy: cy,
            r0: r0,
            r: roseType ? NaN : r
          });
          return;
        }

        if (roseType !== 'area') {
          angle = sum === 0 && stillShowZeroSum ? unitRadian : value * unitRadian;
        } else {
          angle = PI2$6 / validDataCount;
        }

        if (angle < minAngle) {
          angle = minAngle;
          restAngle -= minAngle;
        } else {
          valueSumLargerThanMinAngle += value;
        }

        var endAngle = currentAngle + dir * angle;
        data.setItemLayout(idx, {
          angle: angle,
          startAngle: currentAngle,
          endAngle: endAngle,
          clockwise: clockwise,
          cx: cx,
          cy: cy,
          r0: r0,
          r: roseType ? linearMap(value, extent, [r0, r]) : r
        });
        currentAngle = endAngle;
      });

      if (restAngle < PI2$6 && validDataCount) {
        if (restAngle <= 1e-3) {
          var angle_1 = PI2$6 / validDataCount;
          data.each(valueDim, function (value, idx) {
            if (!isNaN(value)) {
              var layout_1 = data.getItemLayout(idx);
              layout_1.angle = angle_1;
              layout_1.startAngle = startAngle + dir * idx * angle_1;
              layout_1.endAngle = startAngle + dir * (idx + 1) * angle_1;
            }
          });
        } else {
          unitRadian = restAngle / valueSumLargerThanMinAngle;
          currentAngle = startAngle;
          data.each(valueDim, function (value, idx) {
            if (!isNaN(value)) {
              var layout_2 = data.getItemLayout(idx);
              var angle = layout_2.angle === minAngle ? minAngle : value * unitRadian;
              layout_2.startAngle = currentAngle;
              layout_2.endAngle = currentAngle + dir * angle;
              currentAngle += dir * angle;
            }
          });
        }
      }
    });
  }

  function dataFilter(seriesType) {
    return {
      seriesType: seriesType,
      reset: function (seriesModel, ecModel) {
        var legendModels = ecModel.findComponents({
          mainType: 'legend'
        });

        if (!legendModels || !legendModels.length) {
          return;
        }

        var data = seriesModel.getData();
        data.filterSelf(function (idx) {
          var name = data.getName(idx);

          for (var i = 0; i < legendModels.length; i++) {
            if (!legendModels[i].isSelected(name)) {
              return false;
            }
          }

          return true;
        });
      }
    };
  }

  createLegacyDataSelectAction('pie', registerAction);
  registerLayout(curry(pieLayout, 'pie'));
  registerProcessor(dataFilter('pie'));
  exports.PRIORITY = PRIORITY;
  exports.connect = connect;
  exports.dataTool = dataTool;
  exports.dependencies = dependencies;
  exports.disConnect = disConnect;
  exports.disconnect = disconnect;
  exports.dispose = dispose;
  exports.extendChartView = extendChartView;
  exports.extendComponentModel = extendComponentModel;
  exports.extendComponentView = extendComponentView;
  exports.extendSeriesModel = extendSeriesModel;
  exports.getCoordinateSystemDimensions = getCoordinateSystemDimensions;
  exports.getInstanceByDom = getInstanceByDom;
  exports.getInstanceById = getInstanceById;
  exports.getMap = getMap;
  exports.init = init$1;
  exports.registerAction = registerAction;
  exports.registerCoordinateSystem = registerCoordinateSystem;
  exports.registerLayout = registerLayout;
  exports.registerLoading = registerLoading;
  exports.registerLocale = registerLocale;
  exports.registerMap = registerMap;
  exports.registerPostUpdate = registerPostUpdate;
  exports.registerPreprocessor = registerPreprocessor;
  exports.registerProcessor = registerProcessor;
  exports.registerTheme = registerTheme;
  exports.registerTransform = registerTransform;
  exports.registerVisual = registerVisual;
  exports.setCanvasCreator = setCanvasCreator;
  exports.version = version;
  Object.defineProperty(exports, '__esModule', {
    value: true
  });
});